mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 06:23:34 -07:00
Add alembic
This commit is contained in:
parent
7559c66127
commit
3022cc20ec
19 changed files with 2712 additions and 2227 deletions
89
alembic.ini
Normal file
89
alembic.ini
Normal file
|
@ -0,0 +1,89 @@
|
|||
# A generic, single database configuration.
|
||||
|
||||
[alembic]
|
||||
# path to migration scripts
|
||||
script_location = alembic
|
||||
|
||||
# template used to generate migration files
|
||||
# file_template = %%(rev)s_%%(slug)s
|
||||
|
||||
# sys.path path, will be prepended to sys.path if present.
|
||||
# defaults to the current working directory.
|
||||
prepend_sys_path = .
|
||||
|
||||
# timezone to use when rendering the date
|
||||
# within the migration file as well as the filename.
|
||||
# string value is passed to dateutil.tz.gettz()
|
||||
# leave blank for localtime
|
||||
# timezone =
|
||||
|
||||
# max length of characters to apply to the
|
||||
# "slug" field
|
||||
# truncate_slug_length = 40
|
||||
|
||||
# set to 'true' to run the environment during
|
||||
# the 'revision' command, regardless of autogenerate
|
||||
# revision_environment = false
|
||||
|
||||
# set to 'true' to allow .pyc and .pyo files without
|
||||
# a source .py file to be detected as revisions in the
|
||||
# versions/ directory
|
||||
# sourceless = false
|
||||
|
||||
# version location specification; this defaults
|
||||
# to alembic/versions. When using multiple version
|
||||
# directories, initial revisions must be specified with --version-path
|
||||
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
|
||||
|
||||
# the output encoding used when revision files
|
||||
# are written from script.py.mako
|
||||
# output_encoding = utf-8
|
||||
|
||||
sqlalchemy.url = sqlite:///mealie.db
|
||||
|
||||
|
||||
[post_write_hooks]
|
||||
# post_write_hooks defines scripts or Python functions that are run
|
||||
# on newly generated revision scripts. See the documentation for further
|
||||
# detail and examples
|
||||
|
||||
# format using "black" - use the console_scripts runner, against the "black" entrypoint
|
||||
# hooks=black
|
||||
# black.type=console_scripts
|
||||
# black.entrypoint=black
|
||||
# black.options=-l 79
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
qualname =
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
|
||||
[logger_alembic]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
1
alembic/README
Normal file
1
alembic/README
Normal file
|
@ -0,0 +1 @@
|
|||
Generic single-database configuration.
|
79
alembic/env.py
Normal file
79
alembic/env.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
from logging.config import fileConfig
|
||||
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy import pool
|
||||
|
||||
from alembic import context
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
from mealie.db.models.model_base import SqlAlchemyBase as Base
|
||||
import mealie.db.models._all_models
|
||||
target_metadata = Base.metadata
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
# ... etc.
|
||||
|
||||
|
||||
def run_migrations_offline():
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(
|
||||
url=url,
|
||||
target_metadata=target_metadata,
|
||||
literal_binds=True,
|
||||
dialect_opts={"paramstyle": "named"},
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
def run_migrations_online():
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
connectable = engine_from_config(
|
||||
config.get_section(config.config_ini_section),
|
||||
prefix="sqlalchemy.",
|
||||
poolclass=pool.NullPool,
|
||||
)
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
connection=connection, target_metadata=target_metadata
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
24
alembic/script.py.mako
Normal file
24
alembic/script.py.mako
Normal file
|
@ -0,0 +1,24 @@
|
|||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision | comma,n}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
branch_labels = ${repr(branch_labels)}
|
||||
depends_on = ${repr(depends_on)}
|
||||
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
318
alembic/versions/89e8733c36f2_initial_revision.py
Normal file
318
alembic/versions/89e8733c36f2_initial_revision.py
Normal file
|
@ -0,0 +1,318 @@
|
|||
"""Initial revision
|
||||
|
||||
Revision ID: 89e8733c36f2
|
||||
Revises:
|
||||
Create Date: 2021-04-27 23:37:22.500465
|
||||
|
||||
"""
|
||||
from mealie.core.config import settings
|
||||
from mealie.core.security import get_password_hash
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '89e8733c36f2'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
categories_table = op.create_table('categories',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=False),
|
||||
sa.Column('slug', sa.String(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_categories_name'), 'categories', ['name'], unique=False)
|
||||
op.create_index(op.f('ix_categories_slug'), 'categories', ['slug'], unique=True)
|
||||
custom_pages_table = op.create_table('custom_pages',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('position', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=False),
|
||||
sa.Column('slug', sa.String(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
groups_table = op.create_table('groups',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=False),
|
||||
sa.Column('webhook_enable', sa.Boolean(), nullable=True),
|
||||
sa.Column('webhook_time', sa.String(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_groups_name'), 'groups', ['name'], unique=True)
|
||||
recipes_table = op.create_table('recipes',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=False),
|
||||
sa.Column('description', sa.String(), nullable=True),
|
||||
sa.Column('image', sa.String(), nullable=True),
|
||||
sa.Column('totalTime', sa.String(), nullable=True),
|
||||
sa.Column('prepTime', sa.String(), nullable=True),
|
||||
sa.Column('performTime', sa.String(), nullable=True),
|
||||
sa.Column('cookTime', sa.String(), nullable=True),
|
||||
sa.Column('recipeYield', sa.String(), nullable=True),
|
||||
sa.Column('recipeCuisine', sa.String(), nullable=True),
|
||||
sa.Column('slug', sa.String(), nullable=True),
|
||||
sa.Column('dateAdded', sa.Date(), nullable=True),
|
||||
sa.Column('rating', sa.Integer(), nullable=True),
|
||||
sa.Column('orgURL', sa.String(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_recipes_slug'), 'recipes', ['slug'], unique=True)
|
||||
sign_ups_table = op.create_table('sign_ups',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('token', sa.String(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=True),
|
||||
sa.Column('admin', sa.Boolean(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_sign_ups_name'), 'sign_ups', ['name'], unique=False)
|
||||
op.create_index(op.f('ix_sign_ups_token'), 'sign_ups', ['token'], unique=False)
|
||||
site_settings_table = op.create_table('site_settings',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('language', sa.String(), nullable=True),
|
||||
sa.Column('show_recent', sa.Boolean(), nullable=True),
|
||||
sa.Column('cards_per_section', sa.Integer(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
site_theme_table = op.create_table('site_theme',
|
||||
sa.Column('name', sa.String(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('name')
|
||||
)
|
||||
tags_table = op.create_table('tags',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=False),
|
||||
sa.Column('slug', sa.String(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_tags_name'), 'tags', ['name'], unique=False)
|
||||
op.create_index(op.f('ix_tags_slug'), 'tags', ['slug'], unique=True)
|
||||
api_extras_table = op.create_table('api_extras',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('key_name', sa.String(), nullable=True),
|
||||
sa.Column('value', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['recipes.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('key_name')
|
||||
)
|
||||
custom_pages2categories_table = op.create_table('custom_pages2categories',
|
||||
sa.Column('custom_page_id', sa.Integer(), nullable=True),
|
||||
sa.Column('category_slug', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['category_slug'], ['categories.slug'], ),
|
||||
sa.ForeignKeyConstraint(['custom_page_id'], ['custom_pages.id'], )
|
||||
)
|
||||
group2categories_table = op.create_table('group2categories',
|
||||
sa.Column('group_id', sa.Integer(), nullable=True),
|
||||
sa.Column('category_slug', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['category_slug'], ['categories.slug'], ),
|
||||
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], )
|
||||
)
|
||||
mealplan_table = op.create_table('mealplan',
|
||||
sa.Column('uid', sa.Integer(), nullable=False),
|
||||
sa.Column('startDate', sa.Date(), nullable=True),
|
||||
sa.Column('endDate', sa.Date(), nullable=True),
|
||||
sa.Column('group_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('uid'),
|
||||
sa.UniqueConstraint('uid')
|
||||
)
|
||||
notes_table = op.create_table('notes',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('title', sa.String(), nullable=True),
|
||||
sa.Column('text', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['recipes.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
recipe_instructions_table = op.create_table('recipe_instructions',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('position', sa.Integer(), nullable=True),
|
||||
sa.Column('type', sa.String(), nullable=True),
|
||||
sa.Column('text', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['recipes.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
recipe_nutrition_table = op.create_table('recipe_nutrition',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('calories', sa.String(), nullable=True),
|
||||
sa.Column('fatContent', sa.String(), nullable=True),
|
||||
sa.Column('fiberContent', sa.String(), nullable=True),
|
||||
sa.Column('proteinContent', sa.String(), nullable=True),
|
||||
sa.Column('sodiumContent', sa.String(), nullable=True),
|
||||
sa.Column('sugarContent', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['recipes.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
recipes2categories_table = op.create_table('recipes2categories',
|
||||
sa.Column('recipe_id', sa.Integer(), nullable=True),
|
||||
sa.Column('category_slug', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['category_slug'], ['categories.slug'], ),
|
||||
sa.ForeignKeyConstraint(['recipe_id'], ['recipes.id'], )
|
||||
)
|
||||
recipes2tags_table = op.create_table('recipes2tags',
|
||||
sa.Column('recipe_id', sa.Integer(), nullable=True),
|
||||
sa.Column('tag_slug', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['recipe_id'], ['recipes.id'], ),
|
||||
sa.ForeignKeyConstraint(['tag_slug'], ['tags.slug'], )
|
||||
)
|
||||
recipes_ingredients_table = op.create_table('recipes_ingredients',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('position', sa.Integer(), nullable=True),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('ingredient', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['recipes.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
site_settings2categories_table = op.create_table('site_settings2categories_table',
|
||||
sa.Column('sidebar_id', sa.Integer(), nullable=True),
|
||||
sa.Column('category_slug', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['category_slug'], ['categories.slug'], ),
|
||||
sa.ForeignKeyConstraint(['sidebar_id'], ['site_settings.id'], )
|
||||
)
|
||||
theme_colors_table = op.create_table('theme_colors',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('parent_id', sa.String(), nullable=True),
|
||||
sa.Column('primary', sa.String(), nullable=True),
|
||||
sa.Column('accent', sa.String(), nullable=True),
|
||||
sa.Column('secondary', sa.String(), nullable=True),
|
||||
sa.Column('success', sa.String(), nullable=True),
|
||||
sa.Column('info', sa.String(), nullable=True),
|
||||
sa.Column('warning', sa.String(), nullable=True),
|
||||
sa.Column('error', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['site_theme.name'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
tools_table = op.create_table('tools',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('tool', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['recipes.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
users_table = op.create_table('users',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('full_name', sa.String(), nullable=True),
|
||||
sa.Column('email', sa.String(), nullable=True),
|
||||
sa.Column('password', sa.String(), nullable=True),
|
||||
sa.Column('group_id', sa.Integer(), nullable=True),
|
||||
sa.Column('admin', sa.Boolean(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True)
|
||||
op.create_index(op.f('ix_users_full_name'), 'users', ['full_name'], unique=False)
|
||||
webhook_urls_table = op.create_table('webhook_urls',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('url', sa.String(), nullable=True),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
meal_table = op.create_table('meal',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('slug', sa.String(), nullable=True),
|
||||
sa.Column('name', sa.String(), nullable=True),
|
||||
sa.Column('date', sa.Date(), nullable=True),
|
||||
sa.Column('image', sa.String(), nullable=True),
|
||||
sa.Column('description', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['mealplan.uid'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
# seed data
|
||||
op.bulk_insert(site_settings_table, [
|
||||
{
|
||||
"id": 1,
|
||||
"language": "en",
|
||||
"firstDayOfWeek": 0,
|
||||
"showRecent": True,
|
||||
}
|
||||
])
|
||||
op.bulk_insert(categories_table, [
|
||||
{"id": 1, "name": "thanksgiving", "slug": "thanksgiving"},
|
||||
{"id": 2, "name": "homechef", "slug": "homechef"},
|
||||
{"id": 3, "name": "potatoes", "slug": "potatoes"},
|
||||
])
|
||||
op.bulk_insert(site_settings2categories_table, [
|
||||
{
|
||||
"sidebar_id": 1,
|
||||
"category_slug", "thanksgiving",
|
||||
},
|
||||
{
|
||||
"sidebar_id": 1,
|
||||
"category_slug", "homechef",
|
||||
},
|
||||
{
|
||||
"sidebar_id": 1,
|
||||
"category_slug", "potatoes",
|
||||
},
|
||||
])
|
||||
op.bulk_insert(site_theme_table, [
|
||||
{
|
||||
"name": "default",
|
||||
"colors": {
|
||||
"primary": "#E58325",
|
||||
"accent": "#00457A",
|
||||
"secondary": "#973542",
|
||||
"success": "#5AB1BB",
|
||||
"info": "#4990BA",
|
||||
"warning": "#FF4081",
|
||||
"error": "#EF5350",
|
||||
},
|
||||
},
|
||||
])
|
||||
op.bulk_insert(groups_table, [
|
||||
{
|
||||
"name": settings.DEFAULT_GROUP,
|
||||
},
|
||||
])
|
||||
op.bulk_insert(users_table, [
|
||||
{
|
||||
"full_name": "Change Me",
|
||||
"email": settings.DEFAULT_EMAIL,
|
||||
"password": get_password_hash(settings.DEFAULT_PASSWORD),
|
||||
"group": settings.DEFAULT_GROUP,
|
||||
"admin": True,
|
||||
},
|
||||
])
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('meal')
|
||||
op.drop_table('webhook_urls')
|
||||
op.drop_index(op.f('ix_users_full_name'), table_name='users')
|
||||
op.drop_index(op.f('ix_users_email'), table_name='users')
|
||||
op.drop_table('users')
|
||||
op.drop_table('tools')
|
||||
op.drop_table('theme_colors')
|
||||
op.drop_table('site_settings2categories')
|
||||
op.drop_table('recipes_ingredients')
|
||||
op.drop_table('recipes2tags')
|
||||
op.drop_table('recipes2categories')
|
||||
op.drop_table('recipe_nutrition')
|
||||
op.drop_table('recipe_instructions')
|
||||
op.drop_table('notes')
|
||||
op.drop_table('mealplan')
|
||||
op.drop_table('group2categories')
|
||||
op.drop_table('custom_pages2categories')
|
||||
op.drop_table('api_extras')
|
||||
op.drop_index(op.f('ix_tags_slug'), table_name='tags')
|
||||
op.drop_index(op.f('ix_tags_name'), table_name='tags')
|
||||
op.drop_table('tags')
|
||||
op.drop_table('site_theme')
|
||||
op.drop_table('site_settings')
|
||||
op.drop_index(op.f('ix_sign_ups_token'), table_name='sign_ups')
|
||||
op.drop_index(op.f('ix_sign_ups_name'), table_name='sign_ups')
|
||||
op.drop_table('sign_ups')
|
||||
op.drop_index(op.f('ix_recipes_slug'), table_name='recipes')
|
||||
op.drop_table('recipes')
|
||||
op.drop_index(op.f('ix_groups_name'), table_name='groups')
|
||||
op.drop_table('groups')
|
||||
op.drop_table('custom_pages')
|
||||
op.drop_index(op.f('ix_categories_slug'), table_name='categories')
|
||||
op.drop_index(op.f('ix_categories_name'), table_name='categories')
|
||||
op.drop_table('categories')
|
|
@ -123,7 +123,7 @@ The frontend static files are generated with `npm run build`. This is done durin
|
|||
### Backend API
|
||||
The backend API is build with Python, FastAPI, and SQLite and requires Python 3.9, and Poetry. Once the requirements are installed, in the project directory you can run the command `poetry install` to create a python virtual environment and install the python dependencies.
|
||||
|
||||
Once the dependencies are installed you should be ready to run the server. To initialize that database you need to first run `python mealie/db/init_db.py`. Then to start The web server, you run the command `uvicorn mealie.app:app --host 0.0.0.0 --port 9000`
|
||||
Once the dependencies are installed you should be ready to run the server. To initialize that database you need to first run `alembic upgrade head`. Then to start The web server, you run the command `uvicorn mealie.app:app --host 0.0.0.0 --port 9000`
|
||||
|
||||
|
||||
### Proxy Server
|
||||
|
|
2
makefile
2
makefile
|
@ -53,7 +53,7 @@ setup: ## Setup Development Instance
|
|||
cd ..
|
||||
|
||||
backend: ## Start Mealie Backend Development Server
|
||||
poetry run python mealie/db/init_db.py && \
|
||||
poetry run alembic upgrade head && \
|
||||
poetry run python mealie/services/image/minify.py && \
|
||||
poetry run python mealie/app.py
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ from sqlalchemy.orm.session import Session
|
|||
|
||||
from mealie.db.models.db_session import sql_global_init
|
||||
|
||||
sql_exists = True
|
||||
|
||||
SessionLocal = sql_global_init(settings.DB_URL)
|
||||
|
||||
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
from mealie.core import root_logger
|
||||
from mealie.core.config import settings
|
||||
from mealie.core.security import get_password_hash
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import create_session, sql_exists
|
||||
from mealie.schema.settings import SiteSettings
|
||||
from mealie.schema.theme import SiteTheme
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
logger = root_logger.get_logger("init_db")
|
||||
|
||||
|
||||
def init_db(db: Session = None) -> None:
|
||||
if not db:
|
||||
db = create_session()
|
||||
|
||||
default_group_init(db)
|
||||
default_settings_init(db)
|
||||
default_theme_init(db)
|
||||
default_user_init(db)
|
||||
|
||||
db.close()
|
||||
|
||||
|
||||
def default_theme_init(session: Session):
|
||||
db.themes.create(session, SiteTheme().dict())
|
||||
|
||||
|
||||
def default_settings_init(session: Session):
|
||||
document = db.settings.create(session, SiteSettings().dict())
|
||||
logger.info(f"Created Site Settings: \n {document}")
|
||||
|
||||
|
||||
def default_group_init(session: Session):
|
||||
default_group = {"name": settings.DEFAULT_GROUP}
|
||||
logger.info("Generating Default Group")
|
||||
db.groups.create(session, default_group)
|
||||
|
||||
|
||||
def default_user_init(session: Session):
|
||||
default_user = {
|
||||
"full_name": "Change Me",
|
||||
"email": settings.DEFAULT_EMAIL,
|
||||
"password": get_password_hash(settings.DEFAULT_PASSWORD),
|
||||
"group": settings.DEFAULT_GROUP,
|
||||
"admin": True,
|
||||
}
|
||||
|
||||
logger.info("Generating Default User")
|
||||
db.users.create(session, default_user)
|
||||
|
||||
|
||||
def main():
|
||||
if sql_exists:
|
||||
print("Database Exists")
|
||||
else:
|
||||
print("Database Doesn't Exists, Initializing...")
|
||||
init_db()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -13,8 +13,4 @@ def sql_global_init(db_url: str):
|
|||
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
import mealie.db.models._all_models # noqa: F401
|
||||
|
||||
SqlAlchemyBase.metadata.create_all(engine)
|
||||
|
||||
return SessionLocal
|
||||
|
|
|
@ -8,7 +8,7 @@ from sqlalchemy.orm import validates
|
|||
logger = root_logger.get_logger()
|
||||
|
||||
site_settings2categories = sa.Table(
|
||||
"site_settings2categoories",
|
||||
"site_settings2categories",
|
||||
SqlAlchemyBase.metadata,
|
||||
sa.Column("sidebar_id", sa.Integer, sa.ForeignKey("site_settings.id")),
|
||||
sa.Column("category_id", sa.String, sa.ForeignKey("categories.id")),
|
||||
|
|
|
@ -11,11 +11,7 @@ recipes2tags = sa.Table(
|
|||
"recipes2tags",
|
||||
SqlAlchemyBase.metadata,
|
||||
sa.Column("recipe_id", sa.Integer, sa.ForeignKey("recipes.id")),
|
||||
<<<<<<< HEAD
|
||||
sa.Column("tag_id", sa.Integer, sa.ForeignKey("tags.id")),
|
||||
=======
|
||||
sa.Column("tag_slug", sa.String, sa.ForeignKey("tags.slug")),
|
||||
>>>>>>> e2e2ad5 (feat: other databases support)
|
||||
)
|
||||
|
||||
|
||||
|
|
BIN
mealie/mealie.db
Normal file
BIN
mealie/mealie.db
Normal file
Binary file not shown.
|
@ -7,7 +7,7 @@ ARG1=${1:-production}
|
|||
# DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
|
||||
# # Initialize Database Prerun
|
||||
poetry run python /app/mealie/db/init_db.py
|
||||
poetry run alembic upgrade head
|
||||
poetry run python /app/mealie/services/image/minify.py
|
||||
|
||||
# Migrations
|
||||
|
|
|
@ -16,6 +16,7 @@ class SiteSettings(CamelModel):
|
|||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
<<<<<<< HEAD
|
||||
schema_extra = {
|
||||
"example": {
|
||||
"language": "en",
|
||||
|
@ -29,6 +30,8 @@ class SiteSettings(CamelModel):
|
|||
}
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> 0afdaf6 (Add alembic)
|
||||
|
||||
class CustomPageBase(CamelModel):
|
||||
name: str
|
||||
|
|
|
@ -20,17 +20,3 @@ class SiteTheme(BaseModel):
|
|||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
schema_extra = {
|
||||
"example": {
|
||||
"name": "default",
|
||||
"colors": {
|
||||
"primary": "#E58325",
|
||||
"accent": "#00457A",
|
||||
"secondary": "#973542",
|
||||
"success": "#5AB1BB",
|
||||
"info": "#4990BA",
|
||||
"warning": "#FF4081",
|
||||
"error": "#EF5350",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
4202
poetry.lock
generated
4202
poetry.lock
generated
File diff suppressed because it is too large
Load diff
127
pyproject.toml
127
pyproject.toml
|
@ -1,64 +1,65 @@
|
|||
[tool.poetry]
|
||||
name = "mealie"
|
||||
version = "0.3.0"
|
||||
description = "A Recipe Manager"
|
||||
authors = ["Hayden <hay-kot@pm.me>"]
|
||||
license = "MIT"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
start = "mealie.app:main"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
aiofiles = "0.5.0"
|
||||
aniso8601 = "7.0.0"
|
||||
appdirs = "1.4.4"
|
||||
fastapi = "^0.63.0"
|
||||
uvicorn = {extras = ["standard"], version = "^0.13.0"}
|
||||
APScheduler = "^3.6.3"
|
||||
SQLAlchemy = "^1.3.22"
|
||||
Jinja2 = "^2.11.2"
|
||||
python-dotenv = "^0.15.0"
|
||||
python-slugify = "^4.0.1"
|
||||
requests = "^2.25.1"
|
||||
PyYAML = "^5.3.1"
|
||||
extruct = "^0.12.0"
|
||||
scrape-schema-recipe = "^0.1.3"
|
||||
python-multipart = "^0.0.5"
|
||||
fastapi-camelcase = "^1.0.2"
|
||||
bcrypt = "^3.2.0"
|
||||
python-jose = "^3.2.0"
|
||||
passlib = "^1.7.4"
|
||||
lxml = "4.6.2"
|
||||
Pillow = "^8.2.0"
|
||||
pathvalidate = "^2.4.1"
|
||||
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pylint = "^2.6.0"
|
||||
black = "^20.8b1"
|
||||
pytest = "^6.2.1"
|
||||
pytest-cov = "^2.11.0"
|
||||
mkdocs-material = "^7.0.2"
|
||||
flake8 = "^3.9.0"
|
||||
coverage = "^5.5"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
minversion = "6.0"
|
||||
addopts = "-ra -q --cov=mealie"
|
||||
python_files = 'test_*'
|
||||
python_classes = '*Tests'
|
||||
python_functions = 'test_*'
|
||||
testpaths = [
|
||||
"tests",
|
||||
]
|
||||
|
||||
[tool.coverage.report]
|
||||
[tool.poetry]
|
||||
name = "mealie"
|
||||
version = "0.3.0"
|
||||
description = "A Recipe Manager"
|
||||
authors = ["Hayden <hay-kot@pm.me>"]
|
||||
license = "MIT"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
start = "mealie.app:main"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
aiofiles = "0.5.0"
|
||||
aniso8601 = "7.0.0"
|
||||
appdirs = "1.4.4"
|
||||
fastapi = "^0.63.0"
|
||||
uvicorn = {extras = ["standard"], version = "^0.13.0"}
|
||||
APScheduler = "^3.6.3"
|
||||
SQLAlchemy = "^1.3.22"
|
||||
Jinja2 = "^2.11.2"
|
||||
python-dotenv = "^0.15.0"
|
||||
python-slugify = "^4.0.1"
|
||||
requests = "^2.25.1"
|
||||
PyYAML = "^5.3.1"
|
||||
extruct = "^0.12.0"
|
||||
scrape-schema-recipe = "^0.1.3"
|
||||
python-multipart = "^0.0.5"
|
||||
fastapi-camelcase = "^1.0.2"
|
||||
bcrypt = "^3.2.0"
|
||||
python-jose = "^3.2.0"
|
||||
passlib = "^1.7.4"
|
||||
lxml = "4.6.2"
|
||||
Pillow = "^8.2.0"
|
||||
pathvalidate = "^2.4.1"
|
||||
alembic = "^1.5.8"
|
||||
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pylint = "^2.6.0"
|
||||
black = "^20.8b1"
|
||||
pytest = "^6.2.1"
|
||||
pytest-cov = "^2.11.0"
|
||||
mkdocs-material = "^7.0.2"
|
||||
flake8 = "^3.9.0"
|
||||
coverage = "^5.5"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
minversion = "6.0"
|
||||
addopts = "-ra -q --cov=mealie"
|
||||
python_files = 'test_*'
|
||||
python_classes = '*Tests'
|
||||
python_functions = 'test_*'
|
||||
testpaths = [
|
||||
"tests",
|
||||
]
|
||||
|
||||
[tool.coverage.report]
|
||||
skip_empty = true
|
|
@ -5,7 +5,6 @@ from fastapi.testclient import TestClient
|
|||
from mealie.app import app
|
||||
from mealie.core.config import app_dirs, settings
|
||||
from mealie.db.db_setup import generate_session, sql_global_init
|
||||
from mealie.db.init_db import init_db
|
||||
from pytest import fixture
|
||||
|
||||
from tests.app_routes import AppRoutes
|
||||
|
@ -17,7 +16,6 @@ SQLITE_FILE.unlink(missing_ok=True)
|
|||
|
||||
|
||||
TestSessionLocal = sql_global_init(SQLITE_FILE)
|
||||
init_db(TestSessionLocal())
|
||||
|
||||
|
||||
def override_get_db():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue