sort of working, more changes
This commit is contained in:
@ -17,3 +17,5 @@ MYSQL_ROOT_PASSWORD=supersecret
|
|||||||
NEO4J_URI=bolt://neo4j:7687
|
NEO4J_URI=bolt://neo4j:7687
|
||||||
NEO4J_USER=neo4j
|
NEO4J_USER=neo4j
|
||||||
NEO4J_PASSWORD=your_secure_password
|
NEO4J_PASSWORD=your_secure_password
|
||||||
|
|
||||||
|
STANDARD_IMG_SIZE=300x200
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
# Define basedir so it’s available inside the Config class
|
||||||
|
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
SECRET_KEY = os.environ['SECRET_KEY']
|
SECRET_KEY = os.environ['SECRET_KEY']
|
||||||
UPLOAD_FOLDER = os.environ['UPLOAD_FOLDER']
|
UPLOAD_FOLDER = os.environ['UPLOAD_FOLDER']
|
||||||
@ -28,3 +31,11 @@ class Config:
|
|||||||
NEO4J_URI = os.getenv('NEO4J_URI', 'bolt://neo4j:7687')
|
NEO4J_URI = os.getenv('NEO4J_URI', 'bolt://neo4j:7687')
|
||||||
NEO4J_USER = os.getenv('NEO4J_USER', 'neo4j')
|
NEO4J_USER = os.getenv('NEO4J_USER', 'neo4j')
|
||||||
NEO4J_PASSWORD = os.getenv('NEO4J_PASSWORD', 'your_secure_password')
|
NEO4J_PASSWORD = os.getenv('NEO4J_PASSWORD', 'your_secure_password')
|
||||||
|
|
||||||
|
# Override or default upload folder
|
||||||
|
UPLOAD_FOLDER = os.path.join(basedir, "static", "uploads")
|
||||||
|
|
||||||
|
# Standard image size (for placeholders, etc.)
|
||||||
|
STANDARD_IMG_SIZE = tuple(
|
||||||
|
map(int, os.getenv('STANDARD_IMG_SIZE', '300x200').split('x'))
|
||||||
|
)
|
||||||
|
BIN
main-app-new.zip
Normal file
BIN
main-app-new.zip
Normal file
Binary file not shown.
BIN
main-app.zip
BIN
main-app.zip
Binary file not shown.
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 0fcf1e150ae2
|
|
||||||
Revises: 58516c9892e9
|
|
||||||
Create Date: 2025-06-05 09:31:44.116783
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '0fcf1e150ae2'
|
|
||||||
down_revision = '58516c9892e9'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,8 +1,8 @@
|
|||||||
"""auto
|
"""auto
|
||||||
|
|
||||||
Revision ID: 07d152ee2ac2
|
Revision ID: 13e8b68e0737
|
||||||
Revises: 0171b270afc1
|
Revises: 3065b811b58f
|
||||||
Create Date: 2025-06-04 06:24:51.986909
|
Create Date: 2025-06-09 08:05:24.660884
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
@ -10,8 +10,8 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '07d152ee2ac2'
|
revision = '13e8b68e0737'
|
||||||
down_revision = '0171b270afc1'
|
down_revision = '3065b811b58f'
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 1c7cef84b4ae
|
|
||||||
Revises: 26803929dc3e
|
|
||||||
Create Date: 2025-06-04 22:07:43.375613
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '1c7cef84b4ae'
|
|
||||||
down_revision = '26803929dc3e'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('plant', sa.Column('is_verified', sa.Boolean(), nullable=False))
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.drop_column('plant', 'is_verified')
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 1cd7fa3f84ce
|
|
||||||
Revises: e0afd892f86e
|
|
||||||
Create Date: 2025-06-09 02:46:59.792016
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '1cd7fa3f84ce'
|
|
||||||
down_revision = 'e0afd892f86e'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 1edc2e2c93cd
|
|
||||||
Revises: d11c2e8b173a
|
|
||||||
Create Date: 2025-06-09 04:36:51.035371
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '1edc2e2c93cd'
|
|
||||||
down_revision = 'd11c2e8b173a'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,8 +1,8 @@
|
|||||||
"""auto
|
"""auto
|
||||||
|
|
||||||
Revision ID: 00991befbf1d
|
Revision ID: 1f5b1e0b6b05
|
||||||
Revises: 1cd7fa3f84ce
|
Revises: 3426fe15f0ce
|
||||||
Create Date: 2025-06-09 02:54:23.747908
|
Create Date: 2025-06-09 09:41:17.949317
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
@ -10,8 +10,8 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '00991befbf1d'
|
revision = '1f5b1e0b6b05'
|
||||||
down_revision = '1cd7fa3f84ce'
|
down_revision = '3426fe15f0ce'
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 246f5cce6c15
|
|
||||||
Revises: 90401e0dbe75
|
|
||||||
Create Date: 2025-06-09 05:22:52.461981
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '246f5cce6c15'
|
|
||||||
down_revision = '90401e0dbe75'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 263b128622a9
|
|
||||||
Revises: 00991befbf1d
|
|
||||||
Create Date: 2025-06-09 04:06:48.275595
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '263b128622a9'
|
|
||||||
down_revision = '00991befbf1d'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 26803929dc3e
|
|
||||||
Revises: 07d152ee2ac2
|
|
||||||
Create Date: 2025-06-04 06:38:27.377036
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '26803929dc3e'
|
|
||||||
down_revision = '07d152ee2ac2'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 27a65a4e055c
|
|
||||||
Revises: 48d93714beaf
|
|
||||||
Create Date: 2025-06-05 04:23:44.796455
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '27a65a4e055c'
|
|
||||||
down_revision = '48d93714beaf'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 2a0b02a42543
|
|
||||||
Revises: 93b893e47742
|
|
||||||
Create Date: 2025-06-05 02:41:56.741133
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '2a0b02a42543'
|
|
||||||
down_revision = '93b893e47742'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 2fa6feb17477
|
|
||||||
Revises: 9cff183551e1
|
|
||||||
Create Date: 2025-06-05 00:45:39.693560
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '2fa6feb17477'
|
|
||||||
down_revision = '9cff183551e1'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,8 +1,8 @@
|
|||||||
"""auto
|
"""auto
|
||||||
|
|
||||||
Revision ID: 0171b270afc1
|
Revision ID: 3065b811b58f
|
||||||
Revises: 4d9859ada63b
|
Revises: fa22b011d450
|
||||||
Create Date: 2025-06-04 06:20:47.463202
|
Create Date: 2025-06-09 07:41:07.546689
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
@ -10,8 +10,8 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '0171b270afc1'
|
revision = '3065b811b58f'
|
||||||
down_revision = '4d9859ada63b'
|
down_revision = 'fa22b011d450'
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
"""auto
|
"""auto
|
||||||
|
|
||||||
Revision ID: 01e2d617ae49
|
Revision ID: 33e98411843d
|
||||||
Revises: 460dbe73c1bc
|
Revises: c10353a20277
|
||||||
Create Date: 2025-06-09 04:23:50.730127
|
Create Date: 2025-06-09 09:30:42.712274
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
@ -10,8 +10,8 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '01e2d617ae49'
|
revision = '33e98411843d'
|
||||||
down_revision = '460dbe73c1bc'
|
down_revision = 'c10353a20277'
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
|
28
migrations/versions/3426fe15f0ce_auto.py
Normal file
28
migrations/versions/3426fe15f0ce_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: 3426fe15f0ce
|
||||||
|
Revises: 33e98411843d
|
||||||
|
Create Date: 2025-06-09 09:34:33.556990
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '3426fe15f0ce'
|
||||||
|
down_revision = '33e98411843d'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,70 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 373571dfe134
|
|
||||||
Revises: 0fcf1e150ae2
|
|
||||||
Create Date: 2025-06-05 09:38:55.414193
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy.dialects import mysql
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '373571dfe134'
|
|
||||||
down_revision = '0fcf1e150ae2'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('submission_images', sa.Column('file_url', sa.String(length=256), nullable=False))
|
|
||||||
op.add_column('submission_images', sa.Column('uploaded_at', sa.DateTime(), nullable=True))
|
|
||||||
op.drop_column('submission_images', 'is_visible')
|
|
||||||
op.drop_column('submission_images', 'file_path')
|
|
||||||
op.add_column('submissions', sa.Column('submitted_at', sa.DateTime(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('plant_name', sa.String(length=100), nullable=False))
|
|
||||||
op.add_column('submissions', sa.Column('approved', sa.Boolean(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('approved_at', sa.DateTime(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('reviewed_by', sa.Integer(), nullable=True))
|
|
||||||
op.drop_constraint(op.f('submissions_ibfk_1'), 'submissions', type_='foreignkey')
|
|
||||||
op.create_foreign_key(None, 'submissions', 'users', ['reviewed_by'], ['id'])
|
|
||||||
op.drop_column('submissions', 'common_name')
|
|
||||||
op.drop_column('submissions', 'height')
|
|
||||||
op.drop_column('submissions', 'container_size')
|
|
||||||
op.drop_column('submissions', 'timestamp')
|
|
||||||
op.drop_column('submissions', 'price')
|
|
||||||
op.drop_column('submissions', 'plant_id')
|
|
||||||
op.drop_column('submissions', 'width')
|
|
||||||
op.drop_column('submissions', 'health_status')
|
|
||||||
op.drop_column('submissions', 'leaf_count')
|
|
||||||
op.drop_column('submissions', 'potting_mix')
|
|
||||||
op.drop_column('submissions', 'source')
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('submissions', sa.Column('source', mysql.VARCHAR(length=120), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('potting_mix', mysql.VARCHAR(length=255), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('leaf_count', mysql.INTEGER(), autoincrement=False, nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('health_status', mysql.VARCHAR(length=50), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('width', mysql.FLOAT(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('plant_id', mysql.INTEGER(), autoincrement=False, nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('price', mysql.FLOAT(), nullable=False))
|
|
||||||
op.add_column('submissions', sa.Column('timestamp', mysql.DATETIME(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('container_size', mysql.VARCHAR(length=120), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('height', mysql.FLOAT(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('common_name', mysql.VARCHAR(length=120), nullable=False))
|
|
||||||
op.drop_constraint(None, 'submissions', type_='foreignkey')
|
|
||||||
op.create_foreign_key(op.f('submissions_ibfk_1'), 'submissions', 'plant', ['plant_id'], ['id'])
|
|
||||||
op.drop_column('submissions', 'reviewed_by')
|
|
||||||
op.drop_column('submissions', 'approved_at')
|
|
||||||
op.drop_column('submissions', 'approved')
|
|
||||||
op.drop_column('submissions', 'plant_name')
|
|
||||||
op.drop_column('submissions', 'submitted_at')
|
|
||||||
op.add_column('submission_images', sa.Column('file_path', mysql.VARCHAR(length=255), nullable=False))
|
|
||||||
op.add_column('submission_images', sa.Column('is_visible', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True))
|
|
||||||
op.drop_column('submission_images', 'uploaded_at')
|
|
||||||
op.drop_column('submission_images', 'file_url')
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 39f714eda2bf
|
|
||||||
Revises: 6420e024f896
|
|
||||||
Create Date: 2025-06-06 09:50:29.954004
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '39f714eda2bf'
|
|
||||||
down_revision = '6420e024f896'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 3a0b96235583
|
|
||||||
Revises: 263b128622a9
|
|
||||||
Create Date: 2025-06-09 04:13:37.036064
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '3a0b96235583'
|
|
||||||
down_revision = '263b128622a9'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 401f262d79cc
|
|
||||||
Revises: 583fab3f9f80
|
|
||||||
Create Date: 2025-06-05 04:48:49.440383
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '401f262d79cc'
|
|
||||||
down_revision = '583fab3f9f80'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 408c432b5835
|
|
||||||
Revises: 77087ff2442e
|
|
||||||
Create Date: 2025-06-06 08:34:26.804782
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '408c432b5835'
|
|
||||||
down_revision = '77087ff2442e'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,36 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 447ff559592b
|
|
||||||
Revises: 408c432b5835
|
|
||||||
Create Date: 2025-06-06 08:47:25.908940
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '447ff559592b'
|
|
||||||
down_revision = '408c432b5835'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('submissions', sa.Column('vendor_name', sa.String(length=255), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('rating', sa.Integer(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('old_vendor', sa.String(length=255), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('new_vendor', sa.String(length=255), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('alias_reason', sa.Text(), nullable=True))
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.drop_column('submissions', 'alias_reason')
|
|
||||||
op.drop_column('submissions', 'new_vendor')
|
|
||||||
op.drop_column('submissions', 'old_vendor')
|
|
||||||
op.drop_column('submissions', 'rating')
|
|
||||||
op.drop_column('submissions', 'vendor_name')
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 460dbe73c1bc
|
|
||||||
Revises: 3a0b96235583
|
|
||||||
Create Date: 2025-06-09 04:16:30.838677
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '460dbe73c1bc'
|
|
||||||
down_revision = '3a0b96235583'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 48d93714beaf
|
|
||||||
Revises: 761d0f8be3ff
|
|
||||||
Create Date: 2025-06-05 04:20:31.030479
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '48d93714beaf'
|
|
||||||
down_revision = '761d0f8be3ff'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 48fee8a8a3be
|
|
||||||
Revises: af76c66c9075
|
|
||||||
Create Date: 2025-06-05 00:25:55.439874
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '48fee8a8a3be'
|
|
||||||
down_revision = 'af76c66c9075'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 4bdec754b085
|
|
||||||
Revises: 27a65a4e055c
|
|
||||||
Create Date: 2025-06-05 04:34:19.085549
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '4bdec754b085'
|
|
||||||
down_revision = '27a65a4e055c'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 501b54868875
|
|
||||||
Revises: 401f262d79cc
|
|
||||||
Create Date: 2025-06-05 04:51:52.183453
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '501b54868875'
|
|
||||||
down_revision = '401f262d79cc'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 50d5ff358f96
|
|
||||||
Revises: 1c7cef84b4ae
|
|
||||||
Create Date: 2025-06-04 22:14:54.902029
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '50d5ff358f96'
|
|
||||||
down_revision = '1c7cef84b4ae'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/52e805a0163e_auto.py
Normal file
28
migrations/versions/52e805a0163e_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: 52e805a0163e
|
||||||
|
Revises: cb57ad0a3231
|
||||||
|
Create Date: 2025-06-09 09:48:19.311607
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '52e805a0163e'
|
||||||
|
down_revision = 'cb57ad0a3231'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
28
migrations/versions/539c103a1ac4_auto.py
Normal file
28
migrations/versions/539c103a1ac4_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: 539c103a1ac4
|
||||||
|
Revises: b5b29b5b85ae
|
||||||
|
Create Date: 2025-06-09 10:32:37.666108
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '539c103a1ac4'
|
||||||
|
down_revision = 'b5b29b5b85ae'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 58022b5ab921
|
|
||||||
Revises: 50d5ff358f96
|
|
||||||
Create Date: 2025-06-04 22:32:06.203591
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '58022b5ab921'
|
|
||||||
down_revision = '50d5ff358f96'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 583fab3f9f80
|
|
||||||
Revises: 64ec4065d18d
|
|
||||||
Create Date: 2025-06-05 04:47:05.679772
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '583fab3f9f80'
|
|
||||||
down_revision = '64ec4065d18d'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 58516c9892e9
|
|
||||||
Revises: 85da58851d35
|
|
||||||
Create Date: 2025-06-05 05:28:30.947641
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '58516c9892e9'
|
|
||||||
down_revision = '85da58851d35'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 5c85ebc9451b
|
|
||||||
Revises: d8bfe4d4c083
|
|
||||||
Create Date: 2025-06-05 09:47:14.478039
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '5c85ebc9451b'
|
|
||||||
down_revision = 'd8bfe4d4c083'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 6420e024f896
|
|
||||||
Revises: 7d232205181b
|
|
||||||
Create Date: 2025-06-06 09:40:37.498453
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '6420e024f896'
|
|
||||||
down_revision = '7d232205181b'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,44 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 64c1927562cc
|
|
||||||
Revises: fb0243eaa7c3
|
|
||||||
Create Date: 2025-06-06 07:54:00.147383
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy.dialects import mysql
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '64c1927562cc'
|
|
||||||
down_revision = 'fb0243eaa7c3'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('media', sa.Column('plant_id', sa.Integer(), nullable=True))
|
|
||||||
op.add_column('media', sa.Column('update_id', sa.Integer(), nullable=True))
|
|
||||||
op.drop_constraint(op.f('media_ibfk_2'), 'media', type_='foreignkey')
|
|
||||||
op.drop_constraint(op.f('media_ibfk_3'), 'media', type_='foreignkey')
|
|
||||||
op.create_foreign_key(None, 'media', 'plant', ['plant_id'], ['id'])
|
|
||||||
op.create_foreign_key(None, 'media', 'plant_updates', ['update_id'], ['id'])
|
|
||||||
op.drop_column('media', 'uploader_id')
|
|
||||||
op.drop_column('media', 'submission_id')
|
|
||||||
op.drop_column('media', 'caption')
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('media', sa.Column('caption', mysql.VARCHAR(length=255), nullable=True))
|
|
||||||
op.add_column('media', sa.Column('submission_id', mysql.INTEGER(), autoincrement=False, nullable=True))
|
|
||||||
op.add_column('media', sa.Column('uploader_id', mysql.INTEGER(), autoincrement=False, nullable=False))
|
|
||||||
op.drop_constraint(None, 'media', type_='foreignkey')
|
|
||||||
op.drop_constraint(None, 'media', type_='foreignkey')
|
|
||||||
op.create_foreign_key(op.f('media_ibfk_3'), 'media', 'submissions', ['submission_id'], ['id'])
|
|
||||||
op.create_foreign_key(op.f('media_ibfk_2'), 'media', 'users', ['uploader_id'], ['id'])
|
|
||||||
op.drop_column('media', 'update_id')
|
|
||||||
op.drop_column('media', 'plant_id')
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 64ec4065d18d
|
|
||||||
Revises: 4bdec754b085
|
|
||||||
Create Date: 2025-06-05 04:40:02.186807
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '64ec4065d18d'
|
|
||||||
down_revision = '4bdec754b085'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 6539ef5f5419
|
|
||||||
Revises: 39f714eda2bf
|
|
||||||
Create Date: 2025-06-06 10:03:52.256341
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '6539ef5f5419'
|
|
||||||
down_revision = '39f714eda2bf'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 6cb1c3054071
|
|
||||||
Revises: f4987441cc85
|
|
||||||
Create Date: 2025-06-06 09:09:55.403015
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '6cb1c3054071'
|
|
||||||
down_revision = 'f4987441cc85'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/6fcf5e1ad9fa_auto.py
Normal file
28
migrations/versions/6fcf5e1ad9fa_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: 6fcf5e1ad9fa
|
||||||
|
Revises: a7883990430e
|
||||||
|
Create Date: 2025-06-09 10:27:44.541187
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '6fcf5e1ad9fa'
|
||||||
|
down_revision = 'a7883990430e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,46 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 72455429fdaf
|
|
||||||
Revises: 501b54868875
|
|
||||||
Create Date: 2025-06-05 05:07:43.605568
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy.dialects import mysql
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '72455429fdaf'
|
|
||||||
down_revision = '501b54868875'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.create_table('transfer_request',
|
|
||||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
|
||||||
sa.Column('plant_id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('seller_id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('buyer_id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('status', sa.String(length=20), nullable=False),
|
|
||||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
|
||||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
|
||||||
sa.Column('seller_message', sa.String(length=512), nullable=True),
|
|
||||||
sa.Column('buyer_message', sa.String(length=512), nullable=True),
|
|
||||||
sa.ForeignKeyConstraint(['buyer_id'], ['users.id'], ),
|
|
||||||
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
|
||||||
sa.ForeignKeyConstraint(['seller_id'], ['users.id'], ),
|
|
||||||
sa.PrimaryKeyConstraint('id')
|
|
||||||
)
|
|
||||||
op.add_column('plant', sa.Column('data_verified', sa.Boolean(), nullable=False))
|
|
||||||
op.drop_column('plant_ownership_log', 'graph_node_id')
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('plant_ownership_log', sa.Column('graph_node_id', mysql.VARCHAR(length=255), nullable=True))
|
|
||||||
op.drop_column('plant', 'data_verified')
|
|
||||||
op.drop_table('transfer_request')
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,93 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 761d0f8be3ff
|
|
||||||
Revises: ad9ea9d31b58
|
|
||||||
Create Date: 2025-06-05 04:18:09.403526
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy.dialects import mysql
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '761d0f8be3ff'
|
|
||||||
down_revision = 'ad9ea9d31b58'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.drop_table('plant_lineage')
|
|
||||||
op.add_column('plant', sa.Column('updated_at', sa.DateTime(), nullable=True))
|
|
||||||
op.drop_column('plant', 'transferred')
|
|
||||||
op.drop_column('plant', 'status')
|
|
||||||
op.drop_column('plant', 'is_verified')
|
|
||||||
op.drop_column('plant', 'graph_node_id')
|
|
||||||
op.drop_column('plant', 'notes')
|
|
||||||
op.add_column('plant_common_name', sa.Column('created_at', sa.DateTime(), nullable=True))
|
|
||||||
op.alter_column('plant_common_name', 'name',
|
|
||||||
existing_type=mysql.VARCHAR(length=255),
|
|
||||||
type_=sa.String(length=128),
|
|
||||||
existing_nullable=False)
|
|
||||||
op.add_column('plant_ownership_log', sa.Column('date_acquired', sa.DateTime(), nullable=True))
|
|
||||||
op.add_column('plant_ownership_log', sa.Column('transferred', sa.Boolean(), nullable=False))
|
|
||||||
op.add_column('plant_ownership_log', sa.Column('graph_node_id', sa.String(length=255), nullable=True))
|
|
||||||
op.add_column('plant_ownership_log', sa.Column('is_verified', sa.Boolean(), nullable=False))
|
|
||||||
op.drop_column('plant_ownership_log', 'start_time')
|
|
||||||
op.drop_column('plant_ownership_log', 'transfer_note')
|
|
||||||
op.drop_column('plant_ownership_log', 'end_time')
|
|
||||||
op.add_column('plant_scientific_name', sa.Column('created_at', sa.DateTime(), nullable=True))
|
|
||||||
op.alter_column('plant_scientific_name', 'name',
|
|
||||||
existing_type=mysql.VARCHAR(length=255),
|
|
||||||
type_=sa.String(length=256),
|
|
||||||
existing_nullable=False)
|
|
||||||
op.alter_column('tag', 'name',
|
|
||||||
existing_type=mysql.VARCHAR(length=255),
|
|
||||||
type_=sa.String(length=128),
|
|
||||||
existing_nullable=False)
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.alter_column('tag', 'name',
|
|
||||||
existing_type=sa.String(length=128),
|
|
||||||
type_=mysql.VARCHAR(length=255),
|
|
||||||
existing_nullable=False)
|
|
||||||
op.alter_column('plant_scientific_name', 'name',
|
|
||||||
existing_type=sa.String(length=256),
|
|
||||||
type_=mysql.VARCHAR(length=255),
|
|
||||||
existing_nullable=False)
|
|
||||||
op.drop_column('plant_scientific_name', 'created_at')
|
|
||||||
op.add_column('plant_ownership_log', sa.Column('end_time', mysql.DATETIME(), nullable=True))
|
|
||||||
op.add_column('plant_ownership_log', sa.Column('transfer_note', mysql.TEXT(), nullable=True))
|
|
||||||
op.add_column('plant_ownership_log', sa.Column('start_time', mysql.DATETIME(), nullable=False))
|
|
||||||
op.drop_column('plant_ownership_log', 'is_verified')
|
|
||||||
op.drop_column('plant_ownership_log', 'graph_node_id')
|
|
||||||
op.drop_column('plant_ownership_log', 'transferred')
|
|
||||||
op.drop_column('plant_ownership_log', 'date_acquired')
|
|
||||||
op.alter_column('plant_common_name', 'name',
|
|
||||||
existing_type=sa.String(length=128),
|
|
||||||
type_=mysql.VARCHAR(length=255),
|
|
||||||
existing_nullable=False)
|
|
||||||
op.drop_column('plant_common_name', 'created_at')
|
|
||||||
op.add_column('plant', sa.Column('notes', mysql.TEXT(), nullable=True))
|
|
||||||
op.add_column('plant', sa.Column('graph_node_id', mysql.VARCHAR(length=255), nullable=True))
|
|
||||||
op.add_column('plant', sa.Column('is_verified', mysql.TINYINT(display_width=1), autoincrement=False, nullable=False))
|
|
||||||
op.add_column('plant', sa.Column('status', mysql.VARCHAR(length=50), nullable=False))
|
|
||||||
op.add_column('plant', sa.Column('transferred', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True))
|
|
||||||
op.drop_column('plant', 'updated_at')
|
|
||||||
op.create_table('plant_lineage',
|
|
||||||
sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False),
|
|
||||||
sa.Column('child_plant_id', mysql.INTEGER(), autoincrement=False, nullable=False),
|
|
||||||
sa.Column('parent_plant_id', mysql.INTEGER(), autoincrement=False, nullable=False),
|
|
||||||
sa.Column('type', mysql.VARCHAR(length=50), nullable=False),
|
|
||||||
sa.ForeignKeyConstraint(['child_plant_id'], ['plant.id'], name=op.f('plant_lineage_ibfk_1')),
|
|
||||||
sa.ForeignKeyConstraint(['parent_plant_id'], ['plant.id'], name=op.f('plant_lineage_ibfk_2')),
|
|
||||||
sa.PrimaryKeyConstraint('id'),
|
|
||||||
mysql_collate='utf8mb4_0900_ai_ci',
|
|
||||||
mysql_default_charset='utf8mb4',
|
|
||||||
mysql_engine='InnoDB'
|
|
||||||
)
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,38 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 77087ff2442e
|
|
||||||
Revises: 64c1927562cc
|
|
||||||
Create Date: 2025-06-06 08:10:58.028201
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '77087ff2442e'
|
|
||||||
down_revision = '64c1927562cc'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('media', sa.Column('uploader_id', sa.Integer(), nullable=False))
|
|
||||||
op.add_column('media', sa.Column('caption', sa.String(length=255), nullable=True))
|
|
||||||
op.create_foreign_key(None, 'media', 'users', ['uploader_id'], ['id'])
|
|
||||||
op.add_column('submissions', sa.Column('submission_type', sa.String(length=50), nullable=False))
|
|
||||||
op.add_column('submissions', sa.Column('price', sa.Float(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('source', sa.String(length=255), nullable=True))
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.drop_column('submissions', 'source')
|
|
||||||
op.drop_column('submissions', 'price')
|
|
||||||
op.drop_column('submissions', 'submission_type')
|
|
||||||
op.drop_constraint(None, 'media', type_='foreignkey')
|
|
||||||
op.drop_column('media', 'caption')
|
|
||||||
op.drop_column('media', 'uploader_id')
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 7d232205181b
|
|
||||||
Revises: fad6fe2b5e43
|
|
||||||
Create Date: 2025-06-06 09:38:39.786953
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '7d232205181b'
|
|
||||||
down_revision = 'fad6fe2b5e43'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/7d9fc95edc61_auto.py
Normal file
28
migrations/versions/7d9fc95edc61_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: 7d9fc95edc61
|
||||||
|
Revises: fa3de05c91fb
|
||||||
|
Create Date: 2025-06-09 10:10:23.833551
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '7d9fc95edc61'
|
||||||
|
down_revision = 'fa3de05c91fb'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 7dbb6d550055
|
|
||||||
Revises: 72455429fdaf
|
|
||||||
Create Date: 2025-06-05 05:10:43.392181
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '7dbb6d550055'
|
|
||||||
down_revision = '72455429fdaf'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 7dd0c2491053
|
|
||||||
Revises: 6539ef5f5419
|
|
||||||
Create Date: 2025-06-09 02:26:02.002280
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '7dd0c2491053'
|
|
||||||
down_revision = '6539ef5f5419'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 806e94a40aeb
|
|
||||||
Revises: e1cdc5f78f5e
|
|
||||||
Create Date: 2025-06-05 01:11:25.968741
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '806e94a40aeb'
|
|
||||||
down_revision = 'e1cdc5f78f5e'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/80cf84342c5f_auto.py
Normal file
28
migrations/versions/80cf84342c5f_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: 80cf84342c5f
|
||||||
|
Revises: 539c103a1ac4
|
||||||
|
Create Date: 2025-06-09 10:35:15.685799
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '80cf84342c5f'
|
||||||
|
down_revision = '539c103a1ac4'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 85da58851d35
|
|
||||||
Revises: 8cd29b8fb6ec
|
|
||||||
Create Date: 2025-06-05 05:20:46.638884
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '85da58851d35'
|
|
||||||
down_revision = '8cd29b8fb6ec'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 8605e1ff50cd
|
|
||||||
Revises: cab9b8b4d05b
|
|
||||||
Create Date: 2025-06-09 04:53:58.830485
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '8605e1ff50cd'
|
|
||||||
down_revision = 'cab9b8b4d05b'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 8cd29b8fb6ec
|
|
||||||
Revises: 7dbb6d550055
|
|
||||||
Create Date: 2025-06-05 05:12:50.608338
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '8cd29b8fb6ec'
|
|
||||||
down_revision = '7dbb6d550055'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 90401e0dbe75
|
|
||||||
Revises: 8605e1ff50cd
|
|
||||||
Create Date: 2025-06-09 05:15:46.404716
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '90401e0dbe75'
|
|
||||||
down_revision = '8605e1ff50cd'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 93b893e47742
|
|
||||||
Revises: b783b3b43713
|
|
||||||
Create Date: 2025-06-05 02:37:12.714926
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '93b893e47742'
|
|
||||||
down_revision = 'b783b3b43713'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 9b93a2dffe81
|
|
||||||
Revises: c1a4158c8226
|
|
||||||
Create Date: 2025-06-05 01:29:51.402975
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '9b93a2dffe81'
|
|
||||||
down_revision = 'c1a4158c8226'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: 9cff183551e1
|
|
||||||
Revises: 48fee8a8a3be
|
|
||||||
Create Date: 2025-06-05 00:32:07.995675
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '9cff183551e1'
|
|
||||||
down_revision = '48fee8a8a3be'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/9d73ac427e40_auto.py
Normal file
28
migrations/versions/9d73ac427e40_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: 9d73ac427e40
|
||||||
|
Revises: b9234524f710
|
||||||
|
Create Date: 2025-06-09 08:23:23.453209
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '9d73ac427e40'
|
||||||
|
down_revision = 'b9234524f710'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
28
migrations/versions/a10cbbbeb3f6_auto.py
Normal file
28
migrations/versions/a10cbbbeb3f6_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: a10cbbbeb3f6
|
||||||
|
Revises: 9d73ac427e40
|
||||||
|
Create Date: 2025-06-09 08:28:08.962286
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'a10cbbbeb3f6'
|
||||||
|
down_revision = '9d73ac427e40'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
28
migrations/versions/a7883990430e_auto.py
Normal file
28
migrations/versions/a7883990430e_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: a7883990430e
|
||||||
|
Revises: 7d9fc95edc61
|
||||||
|
Create Date: 2025-06-09 10:13:51.730708
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'a7883990430e'
|
||||||
|
down_revision = '7d9fc95edc61'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
28
migrations/versions/ab1a71750f4e_auto.py
Normal file
28
migrations/versions/ab1a71750f4e_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: ab1a71750f4e
|
||||||
|
Revises: 52e805a0163e
|
||||||
|
Create Date: 2025-06-09 09:50:46.848952
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'ab1a71750f4e'
|
||||||
|
down_revision = '52e805a0163e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: ad9ea9d31b58
|
|
||||||
Revises: 2a0b02a42543
|
|
||||||
Create Date: 2025-06-05 03:05:30.311725
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'ad9ea9d31b58'
|
|
||||||
down_revision = '2a0b02a42543'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: af76c66c9075
|
|
||||||
Revises: 58022b5ab921
|
|
||||||
Create Date: 2025-06-04 22:44:12.056714
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'af76c66c9075'
|
|
||||||
down_revision = '58022b5ab921'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/b5b29b5b85ae_auto.py
Normal file
28
migrations/versions/b5b29b5b85ae_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: b5b29b5b85ae
|
||||||
|
Revises: 6fcf5e1ad9fa
|
||||||
|
Create Date: 2025-06-09 10:30:56.308436
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'b5b29b5b85ae'
|
||||||
|
down_revision = '6fcf5e1ad9fa'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: b783b3b43713
|
|
||||||
Revises: bfc7a6bd8abc
|
|
||||||
Create Date: 2025-06-05 02:07:18.572162
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'b783b3b43713'
|
|
||||||
down_revision = 'bfc7a6bd8abc'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/b9234524f710_auto.py
Normal file
28
migrations/versions/b9234524f710_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: b9234524f710
|
||||||
|
Revises: 13e8b68e0737
|
||||||
|
Create Date: 2025-06-09 08:19:19.133720
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'b9234524f710'
|
||||||
|
down_revision = '13e8b68e0737'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: b9c03e1ae0bf
|
|
||||||
Revises: 9b93a2dffe81
|
|
||||||
Create Date: 2025-06-05 01:37:57.483736
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'b9c03e1ae0bf'
|
|
||||||
down_revision = '9b93a2dffe81'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: bfc7a6bd8abc
|
|
||||||
Revises: cc35036a6f94
|
|
||||||
Create Date: 2025-06-05 01:57:23.973531
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'bfc7a6bd8abc'
|
|
||||||
down_revision = 'cc35036a6f94'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/c10353a20277_auto.py
Normal file
28
migrations/versions/c10353a20277_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: c10353a20277
|
||||||
|
Revises: e4ece621c461
|
||||||
|
Create Date: 2025-06-09 09:13:23.016684
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'c10353a20277'
|
||||||
|
down_revision = 'e4ece621c461'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: c1a4158c8226
|
|
||||||
Revises: 806e94a40aeb
|
|
||||||
Create Date: 2025-06-05 01:16:54.451574
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'c1a4158c8226'
|
|
||||||
down_revision = '806e94a40aeb'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: c9495b058ab0
|
|
||||||
Revises: 373571dfe134
|
|
||||||
Create Date: 2025-06-05 09:42:35.228096
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'c9495b058ab0'
|
|
||||||
down_revision = '373571dfe134'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: cab9b8b4d05b
|
|
||||||
Revises: 1edc2e2c93cd
|
|
||||||
Create Date: 2025-06-09 04:42:01.258302
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'cab9b8b4d05b'
|
|
||||||
down_revision = '1edc2e2c93cd'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/cb3ce762cabb_auto.py
Normal file
28
migrations/versions/cb3ce762cabb_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: cb3ce762cabb
|
||||||
|
Revises: ab1a71750f4e
|
||||||
|
Create Date: 2025-06-09 09:57:52.586507
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'cb3ce762cabb'
|
||||||
|
down_revision = 'ab1a71750f4e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
28
migrations/versions/cb57ad0a3231_auto.py
Normal file
28
migrations/versions/cb57ad0a3231_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: cb57ad0a3231
|
||||||
|
Revises: 1f5b1e0b6b05
|
||||||
|
Create Date: 2025-06-09 09:44:00.832472
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'cb57ad0a3231'
|
||||||
|
down_revision = '1f5b1e0b6b05'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: cc35036a6f94
|
|
||||||
Revises: b9c03e1ae0bf
|
|
||||||
Create Date: 2025-06-05 01:45:09.251040
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'cc35036a6f94'
|
|
||||||
down_revision = 'b9c03e1ae0bf'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: d11c2e8b173a
|
|
||||||
Revises: 01e2d617ae49
|
|
||||||
Create Date: 2025-06-09 04:31:08.076159
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'd11c2e8b173a'
|
|
||||||
down_revision = '01e2d617ae49'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: d8bfe4d4c083
|
|
||||||
Revises: c9495b058ab0
|
|
||||||
Create Date: 2025-06-05 09:44:47.740029
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'd8bfe4d4c083'
|
|
||||||
down_revision = 'c9495b058ab0'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,37 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: e0afd892f86e
|
|
||||||
Revises: 7dd0c2491053
|
|
||||||
Create Date: 2025-06-09 02:37:06.190352
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'e0afd892f86e'
|
|
||||||
down_revision = '7dd0c2491053'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.create_table('import_batches',
|
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('export_id', sa.String(length=64), nullable=False),
|
|
||||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('imported_at', sa.DateTime(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint('id'),
|
|
||||||
sa.UniqueConstraint('export_id', 'user_id', name='uix_export_user')
|
|
||||||
)
|
|
||||||
op.create_index(op.f('ix_import_batches_user_id'), 'import_batches', ['user_id'], unique=False)
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.drop_index(op.f('ix_import_batches_user_id'), table_name='import_batches')
|
|
||||||
op.drop_table('import_batches')
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: e1cdc5f78f5e
|
|
||||||
Revises: 2fa6feb17477
|
|
||||||
Create Date: 2025-06-05 00:57:10.914714
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'e1cdc5f78f5e'
|
|
||||||
down_revision = '2fa6feb17477'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,70 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: e34cff15a95e
|
|
||||||
Revises: 5c85ebc9451b
|
|
||||||
Create Date: 2025-06-06 07:34:33.699976
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy.dialects import mysql
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'e34cff15a95e'
|
|
||||||
down_revision = '5c85ebc9451b'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('featured_images', sa.Column('media_id', sa.Integer(), nullable=False))
|
|
||||||
op.drop_constraint(op.f('featured_images_ibfk_1'), 'featured_images', type_='foreignkey')
|
|
||||||
op.create_foreign_key(None, 'featured_images', 'media', ['media_id'], ['id'])
|
|
||||||
op.drop_column('featured_images', 'submission_image_id')
|
|
||||||
op.add_column('image_hearts', sa.Column('media_id', sa.Integer(), nullable=False))
|
|
||||||
op.drop_constraint(op.f('image_hearts_ibfk_1'), 'image_hearts', type_='foreignkey')
|
|
||||||
op.create_foreign_key(None, 'image_hearts', 'media', ['media_id'], ['id'])
|
|
||||||
op.drop_column('image_hearts', 'submission_image_id')
|
|
||||||
op.add_column('media', sa.Column('uploader_id', sa.Integer(), nullable=False))
|
|
||||||
op.add_column('media', sa.Column('submission_id', sa.Integer(), nullable=True))
|
|
||||||
op.drop_constraint(op.f('media_ibfk_2'), 'media', type_='foreignkey')
|
|
||||||
op.drop_constraint(op.f('media_ibfk_3'), 'media', type_='foreignkey')
|
|
||||||
op.create_foreign_key(None, 'media', 'users', ['uploader_id'], ['id'])
|
|
||||||
op.create_foreign_key(None, 'media', 'submissions', ['submission_id'], ['id'])
|
|
||||||
op.drop_column('media', 'update_id')
|
|
||||||
op.drop_column('media', 'plant_id')
|
|
||||||
op.add_column('submissions', sa.Column('submission_type', sa.String(length=50), nullable=False))
|
|
||||||
op.add_column('submissions', sa.Column('price', sa.Float(), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('source', sa.String(length=255), nullable=True))
|
|
||||||
op.alter_column('submissions', 'plant_name',
|
|
||||||
existing_type=mysql.VARCHAR(length=100),
|
|
||||||
nullable=True)
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.alter_column('submissions', 'plant_name',
|
|
||||||
existing_type=mysql.VARCHAR(length=100),
|
|
||||||
nullable=False)
|
|
||||||
op.drop_column('submissions', 'source')
|
|
||||||
op.drop_column('submissions', 'price')
|
|
||||||
op.drop_column('submissions', 'submission_type')
|
|
||||||
op.add_column('media', sa.Column('plant_id', mysql.INTEGER(), autoincrement=False, nullable=True))
|
|
||||||
op.add_column('media', sa.Column('update_id', mysql.INTEGER(), autoincrement=False, nullable=True))
|
|
||||||
op.drop_constraint(None, 'media', type_='foreignkey')
|
|
||||||
op.drop_constraint(None, 'media', type_='foreignkey')
|
|
||||||
op.create_foreign_key(op.f('media_ibfk_3'), 'media', 'plant_updates', ['update_id'], ['id'])
|
|
||||||
op.create_foreign_key(op.f('media_ibfk_2'), 'media', 'plant', ['plant_id'], ['id'])
|
|
||||||
op.drop_column('media', 'submission_id')
|
|
||||||
op.drop_column('media', 'uploader_id')
|
|
||||||
op.add_column('image_hearts', sa.Column('submission_image_id', mysql.INTEGER(), autoincrement=False, nullable=False))
|
|
||||||
op.drop_constraint(None, 'image_hearts', type_='foreignkey')
|
|
||||||
op.create_foreign_key(op.f('image_hearts_ibfk_1'), 'image_hearts', 'submission_images', ['submission_image_id'], ['id'])
|
|
||||||
op.drop_column('image_hearts', 'media_id')
|
|
||||||
op.add_column('featured_images', sa.Column('submission_image_id', mysql.INTEGER(), autoincrement=False, nullable=False))
|
|
||||||
op.drop_constraint(None, 'featured_images', type_='foreignkey')
|
|
||||||
op.create_foreign_key(op.f('featured_images_ibfk_1'), 'featured_images', 'submission_images', ['submission_image_id'], ['id'])
|
|
||||||
op.drop_column('featured_images', 'media_id')
|
|
||||||
# ### end Alembic commands ###
|
|
28
migrations/versions/e4ece621c461_auto.py
Normal file
28
migrations/versions/e4ece621c461_auto.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: e4ece621c461
|
||||||
|
Revises: a10cbbbeb3f6
|
||||||
|
Create Date: 2025-06-09 08:55:16.262879
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'e4ece621c461'
|
||||||
|
down_revision = 'a10cbbbeb3f6'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('media', sa.Column('created_at', sa.DateTime(), nullable=True))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('media', 'created_at')
|
||||||
|
# ### end Alembic commands ###
|
@ -1,28 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: f4987441cc85
|
|
||||||
Revises: 447ff559592b
|
|
||||||
Create Date: 2025-06-06 08:59:55.024371
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'f4987441cc85'
|
|
||||||
down_revision = '447ff559592b'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
pass
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,8 +1,8 @@
|
|||||||
"""auto
|
"""auto
|
||||||
|
|
||||||
Revision ID: 4d9859ada63b
|
Revision ID: fa22b011d450
|
||||||
Revises:
|
Revises:
|
||||||
Create Date: 2025-06-04 06:16:08.829142
|
Create Date: 2025-06-09 06:59:45.406606
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
@ -10,7 +10,7 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '4d9859ada63b'
|
revision = 'fa22b011d450'
|
||||||
down_revision = None
|
down_revision = None
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
@ -18,18 +18,26 @@ depends_on = None
|
|||||||
|
|
||||||
def upgrade():
|
def upgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('import_batches',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('export_id', sa.String(length=64), nullable=False),
|
||||||
|
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('imported_at', sa.DateTime(), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('export_id', 'user_id', name='uix_export_user')
|
||||||
|
)
|
||||||
|
op.create_index(op.f('ix_import_batches_user_id'), 'import_batches', ['user_id'], unique=False)
|
||||||
op.create_table('plant_common_name',
|
op.create_table('plant_common_name',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('name', sa.String(length=255), nullable=False),
|
sa.Column('name', sa.String(length=128), nullable=False),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
sa.PrimaryKeyConstraint('id'),
|
sa.PrimaryKeyConstraint('id'),
|
||||||
sa.UniqueConstraint('name'),
|
|
||||||
sa.UniqueConstraint('name')
|
sa.UniqueConstraint('name')
|
||||||
)
|
)
|
||||||
op.create_table('tag',
|
op.create_table('tag',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('name', sa.String(length=255), nullable=False),
|
sa.Column('name', sa.String(length=128), nullable=False),
|
||||||
sa.PrimaryKeyConstraint('id'),
|
sa.PrimaryKeyConstraint('id'),
|
||||||
sa.UniqueConstraint('name'),
|
|
||||||
sa.UniqueConstraint('name')
|
sa.UniqueConstraint('name')
|
||||||
)
|
)
|
||||||
op.create_table('users',
|
op.create_table('users',
|
||||||
@ -41,18 +49,39 @@ def upgrade():
|
|||||||
sa.Column('excluded_from_analytics', sa.Boolean(), nullable=True),
|
sa.Column('excluded_from_analytics', sa.Boolean(), nullable=True),
|
||||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
sa.PrimaryKeyConstraint('id'),
|
sa.PrimaryKeyConstraint('id'),
|
||||||
sa.UniqueConstraint('email'),
|
|
||||||
sa.UniqueConstraint('email')
|
sa.UniqueConstraint('email')
|
||||||
)
|
)
|
||||||
op.create_table('plant_scientific_name',
|
op.create_table('plant_scientific_name',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('name', sa.String(length=255), nullable=False),
|
sa.Column('name', sa.String(length=256), nullable=False),
|
||||||
sa.Column('common_id', sa.Integer(), nullable=False),
|
sa.Column('common_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['common_id'], ['plant_common_name.id'], ),
|
sa.ForeignKeyConstraint(['common_id'], ['plant_common_name.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id'),
|
sa.PrimaryKeyConstraint('id'),
|
||||||
sa.UniqueConstraint('name'),
|
|
||||||
sa.UniqueConstraint('name')
|
sa.UniqueConstraint('name')
|
||||||
)
|
)
|
||||||
|
op.create_table('submissions',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('submitted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('plant_name', sa.String(length=100), nullable=True),
|
||||||
|
sa.Column('scientific_name', sa.String(length=120), nullable=True),
|
||||||
|
sa.Column('notes', sa.Text(), nullable=True),
|
||||||
|
sa.Column('submission_type', sa.String(length=50), nullable=False),
|
||||||
|
sa.Column('price', sa.Float(), nullable=True),
|
||||||
|
sa.Column('source', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('vendor_name', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('rating', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('old_vendor', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('new_vendor', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('alias_reason', sa.Text(), nullable=True),
|
||||||
|
sa.Column('approved', sa.Boolean(), nullable=True),
|
||||||
|
sa.Column('approved_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('reviewed_by', sa.Integer(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['reviewed_by'], ['users.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
op.create_table('plant',
|
op.create_table('plant',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('uuid', sa.String(length=36), nullable=False),
|
sa.Column('uuid', sa.String(length=36), nullable=False),
|
||||||
@ -61,20 +90,24 @@ def upgrade():
|
|||||||
sa.Column('common_id', sa.Integer(), nullable=False),
|
sa.Column('common_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('scientific_id', sa.Integer(), nullable=False),
|
sa.Column('scientific_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('plant_type', sa.String(length=50), nullable=False),
|
sa.Column('plant_type', sa.String(length=50), nullable=False),
|
||||||
sa.Column('status', sa.String(length=50), nullable=False),
|
|
||||||
sa.Column('notes', sa.Text(), nullable=True),
|
|
||||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
sa.Column('transferred', sa.Boolean(), nullable=True),
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
sa.Column('graph_node_id', sa.String(length=255), nullable=True),
|
sa.Column('data_verified', sa.Boolean(), nullable=False),
|
||||||
sa.ForeignKeyConstraint(['common_id'], ['plant_common_name.id'], ),
|
sa.ForeignKeyConstraint(['common_id'], ['plant_common_name.id'], ),
|
||||||
sa.ForeignKeyConstraint(['owner_id'], ['users.id'], ),
|
sa.ForeignKeyConstraint(['owner_id'], ['users.id'], ),
|
||||||
sa.ForeignKeyConstraint(['scientific_id'], ['plant_scientific_name.id'], ),
|
sa.ForeignKeyConstraint(['scientific_id'], ['plant_scientific_name.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id'),
|
sa.PrimaryKeyConstraint('id'),
|
||||||
sa.UniqueConstraint('custom_slug'),
|
sa.UniqueConstraint('custom_slug'),
|
||||||
sa.UniqueConstraint('custom_slug'),
|
|
||||||
sa.UniqueConstraint('uuid'),
|
|
||||||
sa.UniqueConstraint('uuid')
|
sa.UniqueConstraint('uuid')
|
||||||
)
|
)
|
||||||
|
op.create_table('submission_images',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('submission_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('file_url', sa.String(length=256), nullable=False),
|
||||||
|
sa.Column('uploaded_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['submission_id'], ['submissions.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
op.create_table('grow_logs',
|
op.create_table('grow_logs',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('plant_id', sa.Integer(), nullable=False),
|
sa.Column('plant_id', sa.Integer(), nullable=False),
|
||||||
@ -83,22 +116,13 @@ def upgrade():
|
|||||||
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_table('plant_lineage',
|
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('child_plant_id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('parent_plant_id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('type', sa.String(length=50), nullable=False),
|
|
||||||
sa.ForeignKeyConstraint(['child_plant_id'], ['plant.id'], ),
|
|
||||||
sa.ForeignKeyConstraint(['parent_plant_id'], ['plant.id'], ),
|
|
||||||
sa.PrimaryKeyConstraint('id')
|
|
||||||
)
|
|
||||||
op.create_table('plant_ownership_log',
|
op.create_table('plant_ownership_log',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('plant_id', sa.Integer(), nullable=False),
|
sa.Column('plant_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('start_time', sa.DateTime(), nullable=False),
|
sa.Column('date_acquired', sa.DateTime(), nullable=True),
|
||||||
sa.Column('end_time', sa.DateTime(), nullable=True),
|
sa.Column('transferred', sa.Boolean(), nullable=False),
|
||||||
sa.Column('transfer_note', sa.Text(), nullable=True),
|
sa.Column('is_verified', sa.Boolean(), nullable=False),
|
||||||
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
||||||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
@ -110,24 +134,19 @@ def upgrade():
|
|||||||
sa.ForeignKeyConstraint(['tag_id'], ['tag.id'], ),
|
sa.ForeignKeyConstraint(['tag_id'], ['tag.id'], ),
|
||||||
sa.PrimaryKeyConstraint('plant_id', 'tag_id')
|
sa.PrimaryKeyConstraint('plant_id', 'tag_id')
|
||||||
)
|
)
|
||||||
op.create_table('submissions',
|
op.create_table('transfer_request',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
sa.Column('plant_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('plant_id', sa.Integer(), nullable=True),
|
sa.Column('seller_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('common_name', sa.String(length=120), nullable=False),
|
sa.Column('buyer_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('scientific_name', sa.String(length=120), nullable=True),
|
sa.Column('status', sa.String(length=20), nullable=False),
|
||||||
sa.Column('price', sa.Float(), nullable=False),
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
sa.Column('source', sa.String(length=120), nullable=True),
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
sa.Column('timestamp', sa.DateTime(), nullable=True),
|
sa.Column('seller_message', sa.String(length=512), nullable=True),
|
||||||
sa.Column('height', sa.Float(), nullable=True),
|
sa.Column('buyer_message', sa.String(length=512), nullable=True),
|
||||||
sa.Column('width', sa.Float(), nullable=True),
|
sa.ForeignKeyConstraint(['buyer_id'], ['users.id'], ),
|
||||||
sa.Column('leaf_count', sa.Integer(), nullable=True),
|
|
||||||
sa.Column('potting_mix', sa.String(length=255), nullable=True),
|
|
||||||
sa.Column('container_size', sa.String(length=120), nullable=True),
|
|
||||||
sa.Column('health_status', sa.String(length=50), nullable=True),
|
|
||||||
sa.Column('notes', sa.Text(), nullable=True),
|
|
||||||
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
||||||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
sa.ForeignKeyConstraint(['seller_id'], ['users.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_table('plant_updates',
|
op.create_table('plant_updates',
|
||||||
@ -141,62 +160,58 @@ def upgrade():
|
|||||||
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_table('submission_images',
|
op.create_table('media',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('submission_id', sa.Integer(), nullable=False),
|
sa.Column('file_url', sa.String(length=256), nullable=False),
|
||||||
sa.Column('file_path', sa.String(length=255), nullable=False),
|
sa.Column('uploaded_at', sa.DateTime(), nullable=True),
|
||||||
sa.Column('is_visible', sa.Boolean(), nullable=True),
|
sa.Column('uploader_id', sa.Integer(), nullable=False),
|
||||||
sa.ForeignKeyConstraint(['submission_id'], ['submissions.id'], ),
|
sa.Column('caption', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('plant_id', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('growlog_id', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('update_id', sa.Integer(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['growlog_id'], ['grow_logs.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['update_id'], ['plant_updates.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['uploader_id'], ['users.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_table('featured_images',
|
op.create_table('featured_images',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('submission_image_id', sa.Integer(), nullable=False),
|
sa.Column('media_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('override_text', sa.String(length=255), nullable=True),
|
sa.Column('override_text', sa.String(length=255), nullable=True),
|
||||||
sa.Column('is_featured', sa.Boolean(), nullable=True),
|
sa.Column('is_featured', sa.Boolean(), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['submission_image_id'], ['submission_images.id'], ),
|
sa.ForeignKeyConstraint(['media_id'], ['media.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_table('image_hearts',
|
op.create_table('image_hearts',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('submission_image_id', sa.Integer(), nullable=False),
|
sa.Column('media_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['submission_image_id'], ['submission_images.id'], ),
|
sa.ForeignKeyConstraint(['media_id'], ['media.id'], ),
|
||||||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_table('media',
|
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('file_url', sa.String(length=256), nullable=False),
|
|
||||||
sa.Column('uploaded_at', sa.DateTime(), nullable=True),
|
|
||||||
sa.Column('plant_id', sa.Integer(), nullable=True),
|
|
||||||
sa.Column('growlog_id', sa.Integer(), nullable=True),
|
|
||||||
sa.Column('update_id', sa.Integer(), nullable=True),
|
|
||||||
sa.Column('caption', sa.String(length=255), nullable=True),
|
|
||||||
sa.ForeignKeyConstraint(['growlog_id'], ['grow_logs.id'], ),
|
|
||||||
sa.ForeignKeyConstraint(['plant_id'], ['plant.id'], ),
|
|
||||||
sa.ForeignKeyConstraint(['update_id'], ['plant_updates.id'], ),
|
|
||||||
sa.PrimaryKeyConstraint('id')
|
|
||||||
)
|
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
def downgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
op.drop_table('media')
|
|
||||||
op.drop_table('image_hearts')
|
op.drop_table('image_hearts')
|
||||||
op.drop_table('featured_images')
|
op.drop_table('featured_images')
|
||||||
op.drop_table('submission_images')
|
op.drop_table('media')
|
||||||
op.drop_table('plant_updates')
|
op.drop_table('plant_updates')
|
||||||
op.drop_table('submissions')
|
op.drop_table('transfer_request')
|
||||||
op.drop_table('plant_tags')
|
op.drop_table('plant_tags')
|
||||||
op.drop_table('plant_ownership_log')
|
op.drop_table('plant_ownership_log')
|
||||||
op.drop_table('plant_lineage')
|
|
||||||
op.drop_table('grow_logs')
|
op.drop_table('grow_logs')
|
||||||
|
op.drop_table('submission_images')
|
||||||
op.drop_table('plant')
|
op.drop_table('plant')
|
||||||
|
op.drop_table('submissions')
|
||||||
op.drop_table('plant_scientific_name')
|
op.drop_table('plant_scientific_name')
|
||||||
op.drop_table('users')
|
op.drop_table('users')
|
||||||
op.drop_table('tag')
|
op.drop_table('tag')
|
||||||
op.drop_table('plant_common_name')
|
op.drop_table('plant_common_name')
|
||||||
|
op.drop_index(op.f('ix_import_batches_user_id'), table_name='import_batches')
|
||||||
|
op.drop_table('import_batches')
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
38
migrations/versions/fa3de05c91fb_auto.py
Normal file
38
migrations/versions/fa3de05c91fb_auto.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
"""auto
|
||||||
|
|
||||||
|
Revision ID: fa3de05c91fb
|
||||||
|
Revises: cb3ce762cabb
|
||||||
|
Create Date: 2025-06-09 10:06:16.352992
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'fa3de05c91fb'
|
||||||
|
down_revision = 'cb3ce762cabb'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('plant', sa.Column('mother_uuid', sa.String(length=36), nullable=True))
|
||||||
|
op.add_column('plant', sa.Column('notes', sa.Text(), nullable=True))
|
||||||
|
op.add_column('plant', sa.Column('is_active', sa.Boolean(), nullable=False))
|
||||||
|
op.add_column('plant', sa.Column('featured_media_id', sa.Integer(), nullable=True))
|
||||||
|
op.create_foreign_key(None, 'plant', 'media', ['featured_media_id'], ['id'])
|
||||||
|
op.create_foreign_key(None, 'plant', 'plant', ['mother_uuid'], ['uuid'])
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint(None, 'plant', type_='foreignkey')
|
||||||
|
op.drop_constraint(None, 'plant', type_='foreignkey')
|
||||||
|
op.drop_column('plant', 'featured_media_id')
|
||||||
|
op.drop_column('plant', 'is_active')
|
||||||
|
op.drop_column('plant', 'notes')
|
||||||
|
op.drop_column('plant', 'mother_uuid')
|
||||||
|
# ### end Alembic commands ###
|
@ -1,32 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: fad6fe2b5e43
|
|
||||||
Revises: 6cb1c3054071
|
|
||||||
Create Date: 2025-06-06 09:24:38.663461
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy.dialects import mysql
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'fad6fe2b5e43'
|
|
||||||
down_revision = '6cb1c3054071'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.alter_column('submissions', 'plant_name',
|
|
||||||
existing_type=mysql.VARCHAR(length=100),
|
|
||||||
nullable=True)
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.alter_column('submissions', 'plant_name',
|
|
||||||
existing_type=mysql.VARCHAR(length=100),
|
|
||||||
nullable=False)
|
|
||||||
# ### end Alembic commands ###
|
|
@ -1,38 +0,0 @@
|
|||||||
"""auto
|
|
||||||
|
|
||||||
Revision ID: fb0243eaa7c3
|
|
||||||
Revises: e34cff15a95e
|
|
||||||
Create Date: 2025-06-06 07:43:42.387700
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy.dialects import mysql
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'fb0243eaa7c3'
|
|
||||||
down_revision = 'e34cff15a95e'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.alter_column('submissions', 'plant_name',
|
|
||||||
existing_type=mysql.VARCHAR(length=100),
|
|
||||||
nullable=False)
|
|
||||||
op.drop_column('submissions', 'price')
|
|
||||||
op.drop_column('submissions', 'source')
|
|
||||||
op.drop_column('submissions', 'submission_type')
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.add_column('submissions', sa.Column('submission_type', mysql.VARCHAR(length=50), nullable=False))
|
|
||||||
op.add_column('submissions', sa.Column('source', mysql.VARCHAR(length=255), nullable=True))
|
|
||||||
op.add_column('submissions', sa.Column('price', mysql.FLOAT(), nullable=True))
|
|
||||||
op.alter_column('submissions', 'plant_name',
|
|
||||||
existing_type=mysql.VARCHAR(length=100),
|
|
||||||
nullable=True)
|
|
||||||
# ### end Alembic commands ###
|
|
@ -51,12 +51,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<main class="container">
|
<main class="container">
|
||||||
{% with messages = get_flashed_messages() %}
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
<div class="alert alert-warning">
|
<div class="container mt-3">
|
||||||
{% for message in messages %}
|
{% for category, message in messages %}
|
||||||
<div>{{ message }}</div>
|
<div class="alert alert-{{ category }} alert-dismissible fade show" role="alert">
|
||||||
{% endfor %}
|
{{ message }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
@ -136,7 +136,7 @@ def upload():
|
|||||||
mreader = csv.DictReader(mf)
|
mreader = csv.DictReader(mf)
|
||||||
if mreader.fieldnames != MEDIA_HEADERS:
|
if mreader.fieldnames != MEDIA_HEADERS:
|
||||||
missing = set(MEDIA_HEADERS) - set(mreader.fieldnames or [])
|
missing = set(MEDIA_HEADERS) - set(mreader.fieldnames or [])
|
||||||
extra = set(reader.fieldnames or []) - set(MEDIA_HEADERS)
|
extra = set(mreader.fieldnames or []) - set(MEDIA_HEADERS)
|
||||||
os.remove(tmp_zip.name)
|
os.remove(tmp_zip.name)
|
||||||
flash(f"media.csv header mismatch. Missing: {missing}, Extra: {extra}", "danger")
|
flash(f"media.csv header mismatch. Missing: {missing}, Extra: {extra}", "danger")
|
||||||
return redirect(request.url)
|
return redirect(request.url)
|
||||||
@ -213,13 +213,13 @@ def upload():
|
|||||||
with open(src, "rb") as sf, open(dst, "wb") as df:
|
with open(src, "rb") as sf, open(dst, "wb") as df:
|
||||||
df.write(sf.read())
|
df.write(sf.read())
|
||||||
|
|
||||||
|
# 🔧 FIXED: match your Media model exactly
|
||||||
media = Media(
|
media = Media(
|
||||||
user_id=current_user.id,
|
file_url=f"uploads/{current_user.id}/{plant_obj.id}/{fname}",
|
||||||
plant_id=plant_obj.id,
|
|
||||||
original_filename=os.path.basename(src),
|
|
||||||
path=f"uploads/{current_user.id}/{plant_obj.id}/{fname}",
|
|
||||||
uploaded_at=datetime.fromisoformat(mrow["Uploaded At"]),
|
uploaded_at=datetime.fromisoformat(mrow["Uploaded At"]),
|
||||||
source_type=mrow["Source Type"]
|
uploader_id=current_user.id,
|
||||||
|
caption=mrow["Source Type"],
|
||||||
|
plant_id=plant_obj.id
|
||||||
)
|
)
|
||||||
db.session.add(media)
|
db.session.add(media)
|
||||||
added_media += 1
|
added_media += 1
|
||||||
@ -336,7 +336,7 @@ def review():
|
|||||||
)
|
)
|
||||||
db.session.add(scientific)
|
db.session.add(scientific)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
all_sci = all_scientific[scientific.name.lower()] = scientific
|
all_scientific[scientific.name.lower()] = scientific
|
||||||
|
|
||||||
verified = not suggested or (suggested and accepted)
|
verified = not suggested or (suggested and accepted)
|
||||||
|
|
||||||
@ -352,6 +352,7 @@ def review():
|
|||||||
)
|
)
|
||||||
db.session.add(plant)
|
db.session.add(plant)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
|
|
||||||
log = PlantOwnershipLog(
|
log = PlantOwnershipLog(
|
||||||
plant_id = plant.id,
|
plant_id = plant.id,
|
||||||
user_id = current_user.id,
|
user_id = current_user.id,
|
||||||
|
@ -16,6 +16,7 @@ class Media(db.Model):
|
|||||||
plant_id = db.Column(db.Integer, db.ForeignKey("plant.id"), nullable=True)
|
plant_id = db.Column(db.Integer, db.ForeignKey("plant.id"), nullable=True)
|
||||||
growlog_id = db.Column(db.Integer, db.ForeignKey("grow_logs.id"), nullable=True)
|
growlog_id = db.Column(db.Integer, db.ForeignKey("grow_logs.id"), nullable=True)
|
||||||
update_id = db.Column(db.Integer, db.ForeignKey("plant_updates.id"), nullable=True)
|
update_id = db.Column(db.Integer, db.ForeignKey("plant_updates.id"), nullable=True)
|
||||||
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||||
|
|
||||||
update = db.relationship("PlantUpdate", back_populates="media_items")
|
update = db.relationship("PlantUpdate", back_populates="media_items")
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
# plugins/media/routes.py
|
# plugins/media/routes.py
|
||||||
|
|
||||||
|
import os
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
from flask import (
|
from flask import (
|
||||||
Blueprint,
|
Blueprint,
|
||||||
redirect,
|
redirect,
|
||||||
@ -10,76 +15,139 @@ from flask import (
|
|||||||
current_app,
|
current_app,
|
||||||
jsonify
|
jsonify
|
||||||
)
|
)
|
||||||
from flask_login import current_user, login_required
|
from flask_login import login_required, current_user
|
||||||
import os
|
|
||||||
from app import db
|
from app import db
|
||||||
from .models import Media, ImageHeart, FeaturedImage
|
from .models import Media, ImageHeart, FeaturedImage
|
||||||
|
from plugins.plant.models import Plant
|
||||||
|
|
||||||
bp = Blueprint("media", __name__, template_folder="templates")
|
bp = Blueprint("media", __name__, url_prefix="/media", template_folder="templates")
|
||||||
|
|
||||||
# We store only "YYYY/MM/DD/<uuid>.ext" in Media.file_url.
|
# -----------------------------------------------------------------------------
|
||||||
# All files live under "/app/static/uploads/YYYY/MM/DD/<uuid>.ext" in the container.
|
# Make generate_image_url available in all templates
|
||||||
BASE_UPLOAD_FOLDER = "static/uploads"
|
# -----------------------------------------------------------------------------
|
||||||
ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif"}
|
@bp.app_context_processor
|
||||||
|
def utility_processor():
|
||||||
|
def generate_image_url(path):
|
||||||
|
if path:
|
||||||
|
return url_for("media.media_file", filename=path)
|
||||||
|
w, h = current_app.config.get("STANDARD_IMG_SIZE", (300, 200))
|
||||||
|
return f"https://placehold.co/{w}x{h}"
|
||||||
|
return dict(generate_image_url=generate_image_url)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Helpers & config
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
def allowed_file(filename):
|
def allowed_file(filename):
|
||||||
return (
|
ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else ""
|
||||||
"." in filename
|
return ext in current_app.config.get("ALLOWED_EXTENSIONS", {"png","jpg","jpeg","gif"})
|
||||||
and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
|
|
||||||
)
|
|
||||||
|
|
||||||
@bp.route("/media/", methods=["GET"])
|
def get_upload_path():
|
||||||
|
base = current_app.config.get("UPLOAD_FOLDER", "static/uploads")
|
||||||
|
now = datetime.utcnow()
|
||||||
|
subdir = os.path.join(str(now.year), f"{now.month:02}", f"{now.day:02}")
|
||||||
|
full = os.path.join(base, subdir)
|
||||||
|
os.makedirs(full, exist_ok=True)
|
||||||
|
return full, subdir
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Routes
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
@bp.route("/", methods=["GET"])
|
||||||
def media_index():
|
def media_index():
|
||||||
"""
|
|
||||||
/media/ is not used stand‐alone—redirect back to homepage.
|
|
||||||
"""
|
|
||||||
return redirect(url_for("core_ui.home"))
|
return redirect(url_for("core_ui.home"))
|
||||||
|
|
||||||
@bp.route("/media/files/<path:filename>", methods=["GET"])
|
@bp.route("/files/<path:filename>", methods=["GET"])
|
||||||
def media_file(filename):
|
def media_file(filename):
|
||||||
"""
|
# Strip leading "uploads/" if present
|
||||||
Serve files from "/app/static/uploads/<filename>".
|
if filename.startswith("uploads/"):
|
||||||
Example: GET /media/files/2025/06/07/abcdef1234abcd.jpg
|
filename = filename[len("uploads/"):]
|
||||||
"""
|
folder = current_app.config.get("UPLOAD_FOLDER", "static/uploads")
|
||||||
# Use os.getcwd() to guarantee "/app/static/uploads" (not "/app/app/static/uploads")
|
return send_from_directory(folder, filename)
|
||||||
full_dir = os.path.join(os.getcwd(), BASE_UPLOAD_FOLDER)
|
|
||||||
return send_from_directory(full_dir, filename)
|
|
||||||
|
|
||||||
@bp.route("/media/heart/<int:media_id>", methods=["POST"])
|
@bp.route("/heart/<int:media_id>", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def toggle_heart(media_id):
|
def toggle_heart(media_id):
|
||||||
"""
|
existing = ImageHeart.query.filter_by(user_id=current_user.id, media_id=media_id).first()
|
||||||
Add/remove a "heart" from an image.
|
|
||||||
"""
|
|
||||||
existing = ImageHeart.query.filter_by(
|
|
||||||
user_id=current_user.id, media_id=media_id
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if existing:
|
if existing:
|
||||||
db.session.delete(existing)
|
db.session.delete(existing)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return jsonify({"status": "unhearted"})
|
return jsonify({"status": "unhearted"})
|
||||||
else:
|
heart = ImageHeart(user_id=current_user.id, media_id=media_id)
|
||||||
heart = ImageHeart(user_id=current_user.id, media_id=media_id)
|
db.session.add(heart)
|
||||||
db.session.add(heart)
|
db.session.commit()
|
||||||
db.session.commit()
|
return jsonify({"status": "hearted"})
|
||||||
return jsonify({"status": "hearted"})
|
|
||||||
|
|
||||||
@bp.route("/media/feature/<int:media_id>", methods=["POST"])
|
@bp.route("/add/<string:plant_uuid>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def add_media(plant_uuid):
|
||||||
|
plant = Plant.query.filter_by(uuid=plant_uuid).first_or_404()
|
||||||
|
file = request.files.get("file")
|
||||||
|
if not file or not allowed_file(file.filename):
|
||||||
|
flash("Invalid or missing file.", "danger")
|
||||||
|
return redirect(request.referrer or url_for("plant.edit", uuid_val=plant_uuid))
|
||||||
|
|
||||||
|
ext = file.filename.rsplit(".", 1)[-1].lower()
|
||||||
|
filename = f"{uuid4()}.{ext}"
|
||||||
|
full_path, subdir = get_upload_path()
|
||||||
|
file.save(os.path.join(full_path, filename))
|
||||||
|
|
||||||
|
media = Media(
|
||||||
|
file_url=os.path.join(subdir, filename).replace("\\", "/"),
|
||||||
|
uploader_id=current_user.id,
|
||||||
|
plant_id=plant.id
|
||||||
|
)
|
||||||
|
db.session.add(media)
|
||||||
|
db.session.commit()
|
||||||
|
flash("Media uploaded successfully.", "success")
|
||||||
|
return redirect(request.referrer or url_for("plant.edit", uuid_val=plant_uuid))
|
||||||
|
|
||||||
|
@bp.route("/feature/<int:media_id>", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def set_featured_image(media_id):
|
def set_featured_image(media_id):
|
||||||
"""
|
|
||||||
Toggle featured status on a media item. Only the uploader or an admin may do so.
|
|
||||||
"""
|
|
||||||
media = Media.query.get_or_404(media_id)
|
media = Media.query.get_or_404(media_id)
|
||||||
if (current_user.id != media.uploader_id) and (current_user.role != "admin"):
|
if current_user.id != media.uploader_id and current_user.role != "admin":
|
||||||
flash("Not authorized to set featured image.", "danger")
|
flash("Not authorized to set featured image.", "danger")
|
||||||
return redirect(request.referrer or url_for("core_ui.home"))
|
return redirect(request.referrer or url_for("core_ui.home"))
|
||||||
|
|
||||||
# Remove any existing featured entries for this media
|
|
||||||
FeaturedImage.query.filter_by(media_id=media_id).delete()
|
FeaturedImage.query.filter_by(media_id=media_id).delete()
|
||||||
featured = FeaturedImage(media_id=media_id, is_featured=True)
|
featured = FeaturedImage(media_id=media_id, is_featured=True)
|
||||||
db.session.add(featured)
|
db.session.add(featured)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Image set as featured.", "success")
|
flash("Image set as featured.", "success")
|
||||||
return redirect(request.referrer or url_for("core_ui.home"))
|
return redirect(request.referrer or url_for("plant.edit", uuid_val=media.plant.uuid))
|
||||||
|
|
||||||
|
@bp.route("/delete/<int:media_id>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def delete_media(media_id):
|
||||||
|
media = Media.query.get_or_404(media_id)
|
||||||
|
if current_user.id != media.uploader_id and current_user.role != "admin":
|
||||||
|
flash("Not authorized to delete this media.", "danger")
|
||||||
|
return redirect(request.referrer or url_for("core_ui.home"))
|
||||||
|
|
||||||
|
full_path = os.path.join(current_app.config.get("UPLOAD_FOLDER", "static/uploads"), media.file_url)
|
||||||
|
if os.path.exists(full_path):
|
||||||
|
os.remove(full_path)
|
||||||
|
|
||||||
|
db.session.delete(media)
|
||||||
|
db.session.commit()
|
||||||
|
flash("Media deleted.", "success")
|
||||||
|
return redirect(request.referrer or url_for("plant.edit", uuid_val=media.plant.uuid))
|
||||||
|
|
||||||
|
@bp.route("/rotate/<int:media_id>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def rotate_media(media_id):
|
||||||
|
media = Media.query.get_or_404(media_id)
|
||||||
|
if current_user.id != media.uploader_id and current_user.role != "admin":
|
||||||
|
flash("Not authorized to rotate this media.", "danger")
|
||||||
|
return redirect(request.referrer or url_for("core_ui.home"))
|
||||||
|
|
||||||
|
full_path = os.path.join(current_app.config.get("UPLOAD_FOLDER", "static/uploads"), media.file_url)
|
||||||
|
try:
|
||||||
|
with Image.open(full_path) as img:
|
||||||
|
img.rotate(-90, expand=True).save(full_path)
|
||||||
|
flash("Image rotated successfully.", "success")
|
||||||
|
except Exception as e:
|
||||||
|
flash(f"Failed to rotate image: {e}", "danger")
|
||||||
|
|
||||||
|
return redirect(request.referrer or url_for("plant.edit", uuid_val=media.plant.uuid))
|
||||||
|
@ -1,21 +1,38 @@
|
|||||||
# plugins/media/utils.py
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
from datetime import datetime
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from flask import current_app, url_for
|
||||||
|
from app import db
|
||||||
|
from .models import Media
|
||||||
|
from plugins.plant.models import Plant
|
||||||
|
|
||||||
|
|
||||||
|
def get_upload_path():
|
||||||
|
"""
|
||||||
|
Return (full_disk_path, subdir) based on UTC date,
|
||||||
|
creating directories if needed.
|
||||||
|
e.g. ('/app/static/uploads/2025/06/09', '2025/06/09')
|
||||||
|
"""
|
||||||
|
base = current_app.config.get("UPLOAD_FOLDER", "static/uploads")
|
||||||
|
now = datetime.utcnow()
|
||||||
|
subdir = os.path.join(str(now.year), f"{now.month:02}", f"{now.day:02}")
|
||||||
|
full = os.path.join(base, subdir)
|
||||||
|
os.makedirs(full, exist_ok=True)
|
||||||
|
return full, subdir
|
||||||
|
|
||||||
|
|
||||||
def generate_random_filename(original_filename):
|
def generate_random_filename(original_filename):
|
||||||
"""
|
"""
|
||||||
Returns a random filename preserving the original extension.
|
Preserve extension, randomize base name.
|
||||||
e.g. “abcd1234efgh.jpg” for “myphoto.jpg”.
|
|
||||||
"""
|
"""
|
||||||
ext = os.path.splitext(original_filename)[1].lower() # includes dot, e.g. ".jpg"
|
ext = os.path.splitext(original_filename)[1].lower()
|
||||||
random_name = uuid.uuid4().hex # 32‐char hex string
|
return f"{uuid.uuid4().hex}{ext}"
|
||||||
return f"{random_name}{ext}"
|
|
||||||
|
|
||||||
def strip_metadata_and_save(source_file, destination_path):
|
def strip_metadata_and_save(source_file, destination_path):
|
||||||
"""
|
"""
|
||||||
Opens an image with Pillow, strips EXIF (metadata), and saves it cleanly.
|
Opens an image with Pillow, strips EXIF metadata, and saves it.
|
||||||
Supports common formats (JPEG, PNG).
|
Supports common formats (JPEG, PNG).
|
||||||
"""
|
"""
|
||||||
with Image.open(source_file) as img:
|
with Image.open(source_file) as img:
|
||||||
@ -23,3 +40,72 @@ def strip_metadata_and_save(source_file, destination_path):
|
|||||||
clean_image = Image.new(img.mode, img.size)
|
clean_image = Image.new(img.mode, img.size)
|
||||||
clean_image.putdata(data)
|
clean_image.putdata(data)
|
||||||
clean_image.save(destination_path)
|
clean_image.save(destination_path)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_image_url(path):
|
||||||
|
"""
|
||||||
|
If path is set, route through /media/files/<path>; otherwise
|
||||||
|
return a placehold.co URL sized to STANDARD_IMG_SIZE.
|
||||||
|
"""
|
||||||
|
if path:
|
||||||
|
return url_for("media.media_file", filename=path)
|
||||||
|
w, h = current_app.config.get("STANDARD_IMG_SIZE", (300, 200))
|
||||||
|
return f"https://placehold.co/{w}x{h}"
|
||||||
|
|
||||||
|
|
||||||
|
def save_media_file(file_storage, uploader_id, related_model=None, related_uuid=None):
|
||||||
|
"""
|
||||||
|
- file_storage: Werkzeug FileStorage
|
||||||
|
- uploader_id: current_user.id
|
||||||
|
- related_model: e.g. 'plant'
|
||||||
|
- related_uuid: the Plant.uuid string
|
||||||
|
Returns the new Media instance.
|
||||||
|
"""
|
||||||
|
full_path, subdir = get_upload_path()
|
||||||
|
filename = generate_random_filename(file_storage.filename)
|
||||||
|
disk_path = os.path.join(full_path, filename)
|
||||||
|
file_storage.save(disk_path)
|
||||||
|
|
||||||
|
media = Media(
|
||||||
|
file_url=os.path.join(subdir, filename).replace("\\", "/"),
|
||||||
|
uploader_id=uploader_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# Associate to plant if requested
|
||||||
|
if related_model == "plant" and related_uuid:
|
||||||
|
plant = Plant.query.filter_by(uuid=related_uuid).first()
|
||||||
|
if plant:
|
||||||
|
media.plant_id = plant.id
|
||||||
|
|
||||||
|
db.session.add(media)
|
||||||
|
db.session.commit()
|
||||||
|
return media
|
||||||
|
|
||||||
|
|
||||||
|
def delete_media_file(media):
|
||||||
|
"""
|
||||||
|
Remove file from disk and delete DB record.
|
||||||
|
"""
|
||||||
|
base = current_app.config.get("UPLOAD_FOLDER", "static/uploads")
|
||||||
|
path = os.path.join(base, media.file_url)
|
||||||
|
try:
|
||||||
|
os.remove(path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
db.session.delete(media)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def rotate_media_file(media, angle=-90):
|
||||||
|
"""
|
||||||
|
Rotate the file on disk (in place) and leave DB record intact.
|
||||||
|
"""
|
||||||
|
base = current_app.config.get("UPLOAD_FOLDER", "static/uploads")
|
||||||
|
path = os.path.join(base, media.file_url)
|
||||||
|
try:
|
||||||
|
with Image.open(path) as img:
|
||||||
|
rotated = img.rotate(angle, expand=True)
|
||||||
|
rotated.save(path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# no DB changes needed
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, TextAreaField, BooleanField, SubmitField
|
from wtforms import StringField, TextAreaField, BooleanField, SubmitField, SelectField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import Optional, DataRequired
|
||||||
|
|
||||||
class PlantForm(FlaskForm):
|
class PlantForm(FlaskForm):
|
||||||
name = StringField('Name', validators=[DataRequired()])
|
common_name = SelectField('Common Name', validators=[Optional()], coerce=int)
|
||||||
type = StringField('Type')
|
scientific_name = SelectField('Scientific Name', validators=[Optional()], coerce=int)
|
||||||
notes = TextAreaField('Notes')
|
mother_uuid = SelectField('Mother UUID', validators=[Optional()], coerce=str)
|
||||||
|
plant_type = SelectField('Plant Type', validators=[DataRequired()], choices=[
|
||||||
|
('cutting', 'Cutting'),
|
||||||
|
('tissue_culture', 'Tissue Culture'),
|
||||||
|
('plant', 'Plant'),
|
||||||
|
('seed', 'Seed'),
|
||||||
|
('division', 'Division'),
|
||||||
|
])
|
||||||
|
custom_slug = StringField('Custom Slug', validators=[Optional()])
|
||||||
|
notes = TextAreaField('Notes', validators=[Optional()])
|
||||||
|
data_verified = BooleanField('Data Verified', default=False)
|
||||||
is_active = BooleanField('Active', default=True)
|
is_active = BooleanField('Active', default=True)
|
||||||
submit = SubmitField('Save')
|
submit = SubmitField('Save')
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import uuid as uuid_lib
|
import uuid as uuid_lib
|
||||||
from app import db
|
from app import db
|
||||||
# from plugins.auth.models import User
|
from plugins.media.models import Media # import Media so we can refer to Media.plant_id
|
||||||
|
|
||||||
|
|
||||||
# Association table for Plant ↔ Tag (unchanged)
|
# Association table for Plant ↔ Tag (unchanged)
|
||||||
plant_tags = db.Table(
|
plant_tags = db.Table(
|
||||||
@ -21,7 +20,7 @@ class Tag(db.Model):
|
|||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
name = db.Column(db.String(128), unique=True, nullable=False)
|
name = db.Column(db.String(128), unique=True, nullable=False)
|
||||||
# … any other columns you had …
|
|
||||||
|
|
||||||
class PlantCommonName(db.Model):
|
class PlantCommonName(db.Model):
|
||||||
__tablename__ = 'plant_common_name'
|
__tablename__ = 'plant_common_name'
|
||||||
@ -38,6 +37,7 @@ class PlantCommonName(db.Model):
|
|||||||
cascade='all, delete-orphan'
|
cascade='all, delete-orphan'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PlantScientificName(db.Model):
|
class PlantScientificName(db.Model):
|
||||||
__tablename__ = 'plant_scientific_name'
|
__tablename__ = 'plant_scientific_name'
|
||||||
__table_args__ = {'extend_existing': True}
|
__table_args__ = {'extend_existing': True}
|
||||||
@ -47,22 +47,17 @@ class PlantScientificName(db.Model):
|
|||||||
common_id = db.Column(db.Integer, db.ForeignKey('plant_common_name.id'), nullable=False)
|
common_id = db.Column(db.Integer, db.ForeignKey('plant_common_name.id'), nullable=False)
|
||||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||||
|
|
||||||
# We removed the “plants” relationship from here to avoid backref conflicts.
|
|
||||||
# If you need it, you can still do Plant.query.filter_by(scientific_id=<this id>).
|
|
||||||
|
|
||||||
class PlantOwnershipLog(db.Model):
|
class PlantOwnershipLog(db.Model):
|
||||||
__tablename__ = 'plant_ownership_log'
|
__tablename__ = 'plant_ownership_log'
|
||||||
__table_args__ = {'extend_existing': True}
|
__table_args__ = {'extend_existing': True}
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
plant_id = db.Column(db.Integer, db.ForeignKey('plant.id'), nullable=False)
|
plant_id = db.Column(db.Integer, db.ForeignKey('plant.id'), nullable=False)
|
||||||
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||||
date_acquired = db.Column(db.DateTime, default=datetime.utcnow)
|
date_acquired = db.Column(db.DateTime, default=datetime.utcnow)
|
||||||
transferred = db.Column(db.Boolean, default=False, nullable=False)
|
transferred = db.Column(db.Boolean, default=False, nullable=False)
|
||||||
is_verified = db.Column(db.Boolean, default=False, nullable=False)
|
is_verified = db.Column(db.Boolean, default=False, nullable=False)
|
||||||
|
|
||||||
# Optional: if you ever want to store a pointer to the Neo4j node, you can re-add:
|
|
||||||
# graph_node_id = db.Column(db.String(255), nullable=True)
|
|
||||||
|
|
||||||
user = db.relationship(
|
user = db.relationship(
|
||||||
'plugins.auth.models.User',
|
'plugins.auth.models.User',
|
||||||
@ -70,56 +65,73 @@ class PlantOwnershipLog(db.Model):
|
|||||||
lazy=True
|
lazy=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Plant(db.Model):
|
class Plant(db.Model):
|
||||||
__tablename__ = 'plant'
|
__tablename__ = 'plant'
|
||||||
__table_args__ = {'extend_existing': True}
|
__table_args__ = {'extend_existing': True}
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
uuid = db.Column(db.String(36), default=lambda: str(uuid_lib.uuid4()), unique=True, nullable=False)
|
uuid = db.Column(db.String(36), default=lambda: str(uuid_lib.uuid4()), unique=True, nullable=False)
|
||||||
custom_slug = db.Column(db.String(255), unique=True, nullable=True)
|
custom_slug = db.Column(db.String(255), unique=True, nullable=True)
|
||||||
|
|
||||||
owner_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
owner_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||||
common_id = db.Column(db.Integer, db.ForeignKey('plant_common_name.id'), nullable=False)
|
common_id = db.Column(db.Integer, db.ForeignKey('plant_common_name.id'), nullable=False)
|
||||||
scientific_id = db.Column(db.Integer, db.ForeignKey('plant_scientific_name.id'), nullable=False)
|
scientific_id = db.Column(db.Integer, db.ForeignKey('plant_scientific_name.id'), nullable=False)
|
||||||
|
|
||||||
plant_type = db.Column(db.String(50), nullable=False)
|
mother_uuid = db.Column(db.String(36), db.ForeignKey('plant.uuid'), nullable=True)
|
||||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
||||||
updated_at = db.Column(db.DateTime, onupdate=datetime.utcnow)
|
|
||||||
|
|
||||||
# ─── NEW: Flag that indicates whether the common/scientific name pair was human-verified ─────────────────
|
plant_type = db.Column(db.String(50), nullable=False)
|
||||||
data_verified = db.Column(db.Boolean, default=False, nullable=False)
|
notes = db.Column(db.Text, nullable=True)
|
||||||
|
is_active = db.Column(db.Boolean, default=True, nullable=False)
|
||||||
|
featured_media_id = db.Column(db.Integer, db.ForeignKey('media.id'), nullable=True)
|
||||||
|
|
||||||
# Relationships
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||||
updates = db.relationship(
|
updated_at = db.Column(db.DateTime, onupdate=datetime.utcnow)
|
||||||
'plugins.growlog.models.PlantUpdate',
|
data_verified = db.Column(db.Boolean, default=False, nullable=False)
|
||||||
backref='plant',
|
|
||||||
lazy=True,
|
|
||||||
cascade='all, delete-orphan'
|
|
||||||
)
|
|
||||||
tags = db.relationship(
|
|
||||||
'plugins.plant.models.Tag',
|
|
||||||
secondary=plant_tags,
|
|
||||||
backref='plants',
|
|
||||||
lazy='dynamic'
|
|
||||||
)
|
|
||||||
|
|
||||||
common_name = db.relationship(
|
# ─── FIXED: explicitly join on Media.plant_id ──────────────────────────────
|
||||||
'plugins.plant.models.PlantCommonName',
|
media = db.relationship(
|
||||||
backref=db.backref('plants', lazy='dynamic'),
|
Media,
|
||||||
lazy=True
|
backref='plant',
|
||||||
)
|
lazy=True,
|
||||||
scientific_name = db.relationship(
|
cascade='all, delete-orphan',
|
||||||
'plugins.plant.models.PlantScientificName',
|
foreign_keys=[Media.plant_id]
|
||||||
backref=db.backref('plants', lazy='dynamic'),
|
)
|
||||||
lazy=True
|
|
||||||
)
|
|
||||||
|
|
||||||
ownership_logs = db.relationship(
|
featured_media = db.relationship(
|
||||||
'plugins.plant.models.PlantOwnershipLog',
|
Media,
|
||||||
backref='plant',
|
foreign_keys=[featured_media_id],
|
||||||
lazy=True,
|
uselist=False
|
||||||
cascade='all, delete-orphan'
|
)
|
||||||
)
|
|
||||||
|
updates = db.relationship(
|
||||||
|
'plugins.growlog.models.PlantUpdate',
|
||||||
|
backref='plant',
|
||||||
|
lazy=True,
|
||||||
|
cascade='all, delete-orphan'
|
||||||
|
)
|
||||||
|
tags = db.relationship(
|
||||||
|
Tag,
|
||||||
|
secondary=plant_tags,
|
||||||
|
backref='plants',
|
||||||
|
lazy='dynamic'
|
||||||
|
)
|
||||||
|
common_name = db.relationship(
|
||||||
|
PlantCommonName,
|
||||||
|
backref=db.backref('plants', lazy='dynamic'),
|
||||||
|
lazy=True
|
||||||
|
)
|
||||||
|
scientific_name = db.relationship(
|
||||||
|
PlantScientificName,
|
||||||
|
backref=db.backref('plants', lazy='dynamic'),
|
||||||
|
lazy=True
|
||||||
|
)
|
||||||
|
ownership_logs = db.relationship(
|
||||||
|
PlantOwnershipLog,
|
||||||
|
backref='plant',
|
||||||
|
lazy=True,
|
||||||
|
cascade='all, delete-orphan'
|
||||||
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Plant {self.uuid} ({self.plant_type})>"
|
return f"<Plant {self.uuid} ({self.plant_type})>"
|
||||||
|
@ -1,43 +1,205 @@
|
|||||||
from flask import Blueprint, render_template, redirect, url_for, request, flash
|
from uuid import uuid4
|
||||||
|
from flask import (
|
||||||
|
Blueprint,
|
||||||
|
render_template,
|
||||||
|
redirect,
|
||||||
|
url_for,
|
||||||
|
request,
|
||||||
|
flash,
|
||||||
|
)
|
||||||
|
from flask_login import login_required, current_user
|
||||||
from app import db
|
from app import db
|
||||||
from .models import Plant
|
from .models import Plant, PlantCommonName, PlantScientificName
|
||||||
from .forms import PlantForm
|
from .forms import PlantForm
|
||||||
|
from plugins.media.models import Media
|
||||||
|
from plugins.media.utils import save_media_file, delete_media_file, rotate_media_file, generate_image_url
|
||||||
|
|
||||||
bp = Blueprint('plant', __name__, template_folder='templates')
|
bp = Blueprint(
|
||||||
|
'plant',
|
||||||
|
__name__,
|
||||||
|
url_prefix='/plants',
|
||||||
|
template_folder='templates'
|
||||||
|
)
|
||||||
|
|
||||||
@bp.route('/plants/')
|
# -----------------------------------------------------------------------------
|
||||||
|
# Make generate_image_url available in all templates
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
@bp.app_context_processor
|
||||||
|
def inject_image_helper():
|
||||||
|
return dict(generate_image_url=generate_image_url)
|
||||||
|
|
||||||
|
# ─── LIST ─────────────────────────────────────────────────────────────────────
|
||||||
|
@bp.route('/', methods=['GET'])
|
||||||
|
@login_required
|
||||||
def index():
|
def index():
|
||||||
plants = Plant.query.order_by(Plant.created_at.desc()).all()
|
plants = (
|
||||||
return render_template('plant/index.html', plants=plants)
|
Plant.query
|
||||||
|
.filter_by(owner_id=current_user.id)
|
||||||
|
.order_by(Plant.created_at.desc())
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
stats = {
|
||||||
|
'user_plants': Plant.query.filter_by(owner_id=current_user.id).count(),
|
||||||
|
'user_images': Media.query.filter_by(uploader_id=current_user.id).count(),
|
||||||
|
'total_plants': Plant.query.count(),
|
||||||
|
'total_images': Media.query.count(),
|
||||||
|
}
|
||||||
|
return render_template('plant/index.html', plants=plants, stats=stats)
|
||||||
|
|
||||||
@bp.route('/plants/<int:plant_id>')
|
# ─── CREATE ───────────────────────────────────────────────────────────────────
|
||||||
def detail(plant_id):
|
@bp.route('/create', methods=['GET', 'POST'])
|
||||||
plant = Plant.query.get_or_404(plant_id)
|
@login_required
|
||||||
return render_template('plant/detail.html', plant=plant)
|
|
||||||
|
|
||||||
@bp.route('/plants/new', methods=['GET', 'POST'])
|
|
||||||
def create():
|
def create():
|
||||||
form = PlantForm()
|
form = PlantForm()
|
||||||
if form.validate_on_submit():
|
|
||||||
plant = Plant(
|
|
||||||
name=form.name.data,
|
|
||||||
type=form.type.data,
|
|
||||||
notes=form.notes.data,
|
|
||||||
is_active=form.is_active.data
|
|
||||||
)
|
|
||||||
db.session.add(plant)
|
|
||||||
db.session.commit()
|
|
||||||
flash('Plant created successfully.', 'success')
|
|
||||||
return redirect(url_for('plant.index'))
|
|
||||||
return render_template('plant/form.html', form=form)
|
|
||||||
|
|
||||||
@bp.route('/plants/<int:plant_id>/edit', methods=['GET', 'POST'])
|
# ─── dropdown choices ───────────────────────────────────────────────────────
|
||||||
def edit(plant_id):
|
form.plant_type.choices = [
|
||||||
plant = Plant.query.get_or_404(plant_id)
|
('plant', 'Plant'),
|
||||||
form = PlantForm(obj=plant)
|
('cutting', 'Cutting'),
|
||||||
|
('seed', 'Seed'),
|
||||||
|
('tissue_culture', 'Tissue Culture'),
|
||||||
|
('division', 'Division'),
|
||||||
|
]
|
||||||
|
form.common_name.choices = [
|
||||||
|
(c.id, c.name)
|
||||||
|
for c in PlantCommonName.query.order_by(PlantCommonName.name)
|
||||||
|
]
|
||||||
|
form.scientific_name.choices = [
|
||||||
|
(s.id, s.name)
|
||||||
|
for s in PlantScientificName.query.order_by(PlantScientificName.name)
|
||||||
|
]
|
||||||
|
form.mother_uuid.choices = [('N/A', 'None')] + [
|
||||||
|
(p.uuid, f"{p.common_name.name if p.common_name else 'Unnamed'} – {p.uuid}")
|
||||||
|
for p in Plant.query.order_by(Plant.created_at.desc()).all()
|
||||||
|
]
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
form.populate_obj(plant)
|
new_plant = Plant(
|
||||||
|
uuid=str(uuid4()),
|
||||||
|
owner_id=current_user.id,
|
||||||
|
plant_type=form.plant_type.data,
|
||||||
|
common_id=form.common_name.data,
|
||||||
|
scientific_id=form.scientific_name.data,
|
||||||
|
mother_uuid=(
|
||||||
|
form.mother_uuid.data
|
||||||
|
if form.mother_uuid.data != 'N/A'
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
custom_slug=form.custom_slug.data,
|
||||||
|
notes=form.notes.data,
|
||||||
|
data_verified=form.data_verified.data,
|
||||||
|
is_active=form.is_active.data,
|
||||||
|
)
|
||||||
|
db.session.add(new_plant)
|
||||||
|
db.session.commit()
|
||||||
|
flash('New plant created successfully.', 'success')
|
||||||
|
return redirect(url_for('plant.edit', uuid_val=new_plant.uuid))
|
||||||
|
|
||||||
|
return render_template('plant/create.html', form=form)
|
||||||
|
|
||||||
|
# ─── DETAIL ───────────────────────────────────────────────────────────────────
|
||||||
|
@bp.route('/<uuid:uuid_val>', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def detail(uuid_val):
|
||||||
|
plant = Plant.query.filter_by(uuid=str(uuid_val)).first_or_404()
|
||||||
|
return render_template('plant/detail.html', plant=plant)
|
||||||
|
|
||||||
|
# ─── EDIT ─────────────────────────────────────────────────────────────────────
|
||||||
|
@bp.route('/<uuid:uuid_val>/edit', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def edit(uuid_val):
|
||||||
|
plant = Plant.query.filter_by(uuid=str(uuid_val)).first_or_404()
|
||||||
|
form = PlantForm()
|
||||||
|
|
||||||
|
form.plant_type.choices = [
|
||||||
|
('plant', 'Plant'),
|
||||||
|
('cutting', 'Cutting'),
|
||||||
|
('seed', 'Seed'),
|
||||||
|
('tissue_culture', 'Tissue Culture'),
|
||||||
|
('division', 'Division'),
|
||||||
|
]
|
||||||
|
form.common_name.choices = [
|
||||||
|
(c.id, c.name)
|
||||||
|
for c in PlantCommonName.query.order_by(PlantCommonName.name)
|
||||||
|
]
|
||||||
|
form.scientific_name.choices = [
|
||||||
|
(s.id, s.name)
|
||||||
|
for s in PlantScientificName.query.order_by(PlantScientificName.name)
|
||||||
|
]
|
||||||
|
form.mother_uuid.choices = [('N/A', 'None')] + [
|
||||||
|
(p.uuid, f"{p.common_name.name if p.common_name else 'Unnamed'} – {p.uuid}")
|
||||||
|
for p in Plant.query.filter(Plant.uuid != plant.uuid).all()
|
||||||
|
]
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
form.plant_type.data = plant.plant_type
|
||||||
|
form.common_name.data = plant.common_id
|
||||||
|
form.scientific_name.data = plant.scientific_id
|
||||||
|
form.mother_uuid.data = plant.mother_uuid or 'N/A'
|
||||||
|
form.custom_slug.data = plant.custom_slug
|
||||||
|
form.notes.data = plant.notes
|
||||||
|
form.data_verified.data = plant.data_verified
|
||||||
|
form.is_active.data = getattr(plant, 'is_active', True)
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
plant.plant_type = form.plant_type.data
|
||||||
|
plant.common_id = form.common_name.data
|
||||||
|
plant.scientific_id = form.scientific_name.data
|
||||||
|
plant.mother_uuid = (
|
||||||
|
form.mother_uuid.data
|
||||||
|
if form.mother_uuid.data != 'N/A'
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
plant.custom_slug = form.custom_slug.data
|
||||||
|
plant.notes = form.notes.data
|
||||||
|
plant.data_verified = form.data_verified.data
|
||||||
|
plant.is_active = form.is_active.data
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash('Plant updated successfully.', 'success')
|
flash('Plant updated successfully.', 'success')
|
||||||
return redirect(url_for('plant.detail', plant_id=plant.id))
|
return redirect(url_for('plant.detail', uuid_val=plant.uuid))
|
||||||
return render_template('plant/form.html', form=form, plant=plant)
|
|
||||||
|
return render_template('plant/edit.html', form=form, plant=plant)
|
||||||
|
|
||||||
|
# ─── IMAGE ROUTES ────────────────────────────────────────────────────────────
|
||||||
|
@bp.route('/<uuid:uuid_val>/upload', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def upload_image(uuid_val):
|
||||||
|
plant = Plant.query.filter_by(uuid=uuid_val).first_or_404()
|
||||||
|
file = request.files.get('file')
|
||||||
|
if file and file.filename:
|
||||||
|
save_media_file(
|
||||||
|
file,
|
||||||
|
current_user.id,
|
||||||
|
related_model='plant',
|
||||||
|
related_uuid=str(plant.uuid)
|
||||||
|
)
|
||||||
|
flash('Image uploaded successfully.', 'success')
|
||||||
|
return redirect(url_for('plant.edit', uuid_val=plant.uuid))
|
||||||
|
|
||||||
|
@bp.route('/<uuid:uuid_val>/feature/<int:media_id>', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def set_featured_image(uuid_val, media_id):
|
||||||
|
plant = Plant.query.filter_by(uuid=uuid_val).first_or_404()
|
||||||
|
media = Media.query.get_or_404(media_id)
|
||||||
|
plant.featured_media_id = media.id
|
||||||
|
db.session.commit()
|
||||||
|
flash('Featured image set.', 'success')
|
||||||
|
return redirect(url_for('plant.edit', uuid_val=plant.uuid))
|
||||||
|
|
||||||
|
@bp.route('/<uuid:uuid_val>/delete/<int:media_id>', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def delete_image(uuid_val, media_id):
|
||||||
|
plant = Plant.query.filter_by(uuid=uuid_val).first_or_404()
|
||||||
|
media = Media.query.get_or_404(media_id)
|
||||||
|
delete_media_file(media)
|
||||||
|
flash('Image deleted.', 'success')
|
||||||
|
return redirect(url_for('plant.edit', uuid_val=plant.uuid))
|
||||||
|
|
||||||
|
@bp.route('/<uuid:uuid_val>/rotate/<int:media_id>', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def rotate_image(uuid_val, media_id):
|
||||||
|
plant = Plant.query.filter_by(uuid=uuid_val).first_or_404()
|
||||||
|
media = Media.query.get_or_404(media_id)
|
||||||
|
rotate_media_file(media)
|
||||||
|
flash('Image rotated.', 'success')
|
||||||
|
return redirect(url_for('plant.edit', uuid_val=plant.uuid))
|
||||||
|
53
plugins/plant/templates/plant/create.html
Normal file
53
plugins/plant/templates/plant/create.html
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{% extends 'core_ui/base.html' %}
|
||||||
|
{% block title %}Add New Plant – Nature In Pots{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h2>Create New Plant</h2>
|
||||||
|
<form method="POST">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.plant_type.label(class="form-label") }}
|
||||||
|
{{ form.plant_type(class="form-select") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.common_name.label(class="form-label") }}
|
||||||
|
{{ form.common_name(class="form-select") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.scientific_name.label(class="form-label") }}
|
||||||
|
{{ form.scientific_name(class="form-select") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.mother_uuid.label(class="form-label") }}
|
||||||
|
{{ form.mother_uuid(class="form-select") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.custom_slug.label(class="form-label") }}
|
||||||
|
{{ form.custom_slug(class="form-control") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.notes.label(class="form-label") }}
|
||||||
|
{{ form.notes(class="form-control", rows=4) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
{{ form.data_verified(class="form-check-input") }}
|
||||||
|
{{ form.data_verified.label(class="form-check-label") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
{{ form.is_active(class="form-check-input") }}
|
||||||
|
{{ form.is_active.label(class="form-check-label") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-success">Create Plant</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -1,37 +1,73 @@
|
|||||||
|
{# plugins/plant/templates/plant/detail.html #}
|
||||||
{% extends 'core_ui/base.html' %}
|
{% extends 'core_ui/base.html' %}
|
||||||
{% block title %}{{ plant.common_name.name }} – Nature In Pots{% endblock %}
|
|
||||||
|
{% block title %}
|
||||||
|
{{ plant.common_name.name if plant.common_name else "Unnamed Plant" }} – Nature In Pots
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container my-4">
|
<div class="container my-4">
|
||||||
<div class="row">
|
<div class="row gx-4">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<img src="https://placehold.co/300x300"
|
{# determine featured or fallback to first media item #}
|
||||||
class="img-fluid rounded mb-3"
|
{% set featured = plant.featured_media or plant.media|first %}
|
||||||
alt="{{ plant.common_name.name }}">
|
<img
|
||||||
|
src="{{ generate_image_url(featured.file_url if featured else None) }}"
|
||||||
|
alt="Image of {{ plant.common_name.name if plant.common_name else 'Plant' }}"
|
||||||
|
class="img-fluid rounded shadow-sm"
|
||||||
|
style="object-fit: cover; width: 100%; height: auto;"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<h1>{{ plant.common_name.name }}</h1>
|
<h2>
|
||||||
|
{{ plant.common_name.name if plant.common_name else "Unnamed Plant" }}
|
||||||
|
</h2>
|
||||||
{% if plant.scientific_name %}
|
{% if plant.scientific_name %}
|
||||||
<p class="text-muted"><em>{{ plant.scientific_name.name }}</em></p>
|
<h5 class="text-muted">
|
||||||
|
{{ plant.scientific_name.name }}
|
||||||
|
</h5>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<dl class="row">
|
|
||||||
<dt class="col-sm-3">Date Added</dt>
|
|
||||||
<dd class="col-sm-9">{{ plant.created_at.strftime('%Y-%m-%d') }}</dd>
|
|
||||||
|
|
||||||
<dt class="col-sm-3">Status</dt>
|
<p class="mt-3">
|
||||||
<dd class="col-sm-9">
|
{{ plant.notes or "No description provided." }}
|
||||||
{{ 'Dead' if plant.is_dead else 'Active' }}
|
</p>
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<a href="{{ url_for('plant.index') }}" class="btn btn-secondary">
|
{% if plant.mother_uuid %}
|
||||||
← Back to list
|
<p class="text-muted">
|
||||||
</a>
|
Parent:
|
||||||
<a href="{{ url_for('plant.edit', plant_id=plant.id) }}"
|
<a href="{{ url_for('plant.detail', uuid_val=plant.mother_uuid) }}">
|
||||||
class="btn btn-primary">
|
{{ plant.mother_uuid }}
|
||||||
Edit
|
</a>
|
||||||
</a>
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<a
|
||||||
|
href="{{ url_for('plant.edit', uuid_val=plant.uuid) }}"
|
||||||
|
class="btn btn-primary me-2"
|
||||||
|
>Edit</a>
|
||||||
|
<a
|
||||||
|
href="{{ url_for('plant.index') }}"
|
||||||
|
class="btn btn-secondary"
|
||||||
|
>Back to List</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if plant.media|length > (1 if plant.featured_media else 0) %}
|
||||||
|
<hr class="my-4">
|
||||||
|
<h4>Additional Images</h4>
|
||||||
|
<div class="d-flex flex-wrap gap-3">
|
||||||
|
{% for img in plant.media if img != featured %}
|
||||||
|
<img
|
||||||
|
src="{{ generate_image_url(img.file_url) }}"
|
||||||
|
alt="Plant image"
|
||||||
|
class="img-thumbnail"
|
||||||
|
style="height: 160px; object-fit: cover;"
|
||||||
|
>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
127
plugins/plant/templates/plant/edit.html
Normal file
127
plugins/plant/templates/plant/edit.html
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
{% extends 'core_ui/base.html' %}
|
||||||
|
{% block title %}Edit Plant – Nature In Pots{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h2>Edit Plant</h2>
|
||||||
|
|
||||||
|
{# ─── Main plant‐data form ──────────────────────────────────────────── #}
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.plant_type.label(class="form-label") }}
|
||||||
|
{{ form.plant_type(class="form-select") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.common_name.label(class="form-label") }}
|
||||||
|
{{ form.common_name(class="form-select") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.scientific_name.label(class="form-label") }}
|
||||||
|
{{ form.scientific_name(class="form-select") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.mother_uuid.label(class="form-label") }}
|
||||||
|
{{ form.mother_uuid(class="form-select") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.custom_slug.label(class="form-label") }}
|
||||||
|
{{ form.custom_slug(class="form-control") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.notes.label(class="form-label") }}
|
||||||
|
{{ form.notes(class="form-control", rows=4) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
{{ form.data_verified(class="form-check-input") }}
|
||||||
|
{{ form.data_verified.label(class="form-check-label") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
{{ form.is_active(class="form-check-input") }}
|
||||||
|
{{ form.is_active.label(class="form-check-label") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
{# ─── Upload new image ─────────────────────────────────────────────── #}
|
||||||
|
<h4>Upload Image</h4>
|
||||||
|
<form
|
||||||
|
method="POST"
|
||||||
|
action="{{ url_for('plant.upload_image', uuid_val=plant.uuid) }}"
|
||||||
|
enctype="multipart/form-data"
|
||||||
|
class="mb-4"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="csrf_token"
|
||||||
|
value="{{ csrf_token() }}"
|
||||||
|
>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="file" name="file" class="form-control" required>
|
||||||
|
<button class="btn btn-secondary" type="submit">Upload</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{# ─── Existing images ──────────────────────────────────────────────── #}
|
||||||
|
<h4>Existing Images</h4>
|
||||||
|
<div class="row">
|
||||||
|
{% for media in plant.media %}
|
||||||
|
<div class="col-md-3 mb-4">
|
||||||
|
<div class="card h-100">
|
||||||
|
<img
|
||||||
|
src="{{ generate_image_url(media.file_url) }}"
|
||||||
|
class="card-img-top img-fluid"
|
||||||
|
alt="Plant Image"
|
||||||
|
style="object-fit:cover; height:150px;"
|
||||||
|
>
|
||||||
|
<div class="card-body text-center">
|
||||||
|
{% if plant.featured_media_id == media.id %}
|
||||||
|
<span class="badge bg-success mb-2">Featured</span>
|
||||||
|
{% else %}
|
||||||
|
<form
|
||||||
|
method="POST"
|
||||||
|
action="{{ url_for('plant.set_featured_image', uuid_val=plant.uuid, media_id=media.id) }}"
|
||||||
|
class="mb-2"
|
||||||
|
>
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<button class="btn btn-outline-primary btn-sm">Set Featured</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="d-grid gap-1">
|
||||||
|
<form
|
||||||
|
method="POST"
|
||||||
|
action="{{ url_for('plant.rotate_image', uuid_val=plant.uuid, media_id=media.id) }}"
|
||||||
|
>
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<button class="btn btn-outline-secondary btn-sm">Rotate</button>
|
||||||
|
</form>
|
||||||
|
<form
|
||||||
|
method="POST"
|
||||||
|
action="{{ url_for('plant.delete_image', uuid_val=plant.uuid, media_id=media.id) }}"
|
||||||
|
onsubmit="return confirm('Delete this image?');"
|
||||||
|
>
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<button class="btn btn-outline-danger btn-sm">Delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-muted">No images uploaded yet.</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -1,12 +0,0 @@
|
|||||||
{% extends 'core_ui/base.html' %}
|
|
||||||
{% block content %}
|
|
||||||
<h1>{% if plant %}Edit{% else %}New{% endif %} Plant</h1>
|
|
||||||
<form method="POST">
|
|
||||||
{{ form.hidden_tag() }}
|
|
||||||
<p>{{ form.name.label }}<br>{{ form.name(size=40) }}</p>
|
|
||||||
<p>{{ form.type.label }}<br>{{ form.type(size=40) }}</p>
|
|
||||||
<p>{{ form.notes.label }}<br>{{ form.notes(rows=5, cols=40) }}</p>
|
|
||||||
<p>{{ form.is_active() }} {{ form.is_active.label }}</p>
|
|
||||||
<p>{{ form.submit() }}</p>
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user