Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .env → .example.env
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ FIRST_SUPERUSER=admin@example.com
FIRST_SUPERUSER_PASSWORD=changethis

# Emails
SMTP_HOST=
SMTP_HOST=localhost
SMTP_USER=
SMTP_PASSWORD=
EMAILS_FROM_EMAIL=info@example.com
SMTP_TLS=True
EMAILS_FROM_EMAIL=noreply@example.com
EMAILS_FROM_NAME="My FastAPI Project"
SMTP_TLS=False
SMTP_SSL=False
SMTP_PORT=587
SMTP_PORT=1025

# Postgres
POSTGRES_SERVER=localhost
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ node_modules/
/playwright-report/
/blob-report/
/playwright/.cache/
*.gen.ts
*.gen.tsx
.env
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
- 🔒 Secure password hashing by default.
- 🔑 JWT (JSON Web Token) authentication.
- 📫 Email based password recovery.
- 📬 [Mailcatcher](https://mailcatcher.me) for local email testing during development.
- 📬 [Mailpit](https://github.com/axllent/mailpit) for local email testing during development.
- ✅ Tests with [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) as a reverse proxy / load balancer.
- 🚢 Deployment instructions using Docker Compose, including how to set up a frontend Traefik proxy to handle automatic HTTPS certificates.
Expand Down
3 changes: 1 addition & 2 deletions backend/app/alembic/env.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import os
from logging.config import fileConfig

from alembic import context
Expand All @@ -20,7 +19,7 @@
# target_metadata = None

from app.models import SQLModel # noqa
from app.core.config import settings # noqa
from app.core.config import settings # noqa

target_metadata = SQLModel.metadata

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,30 @@
Create Date: 2024-07-31 22:24:34.447891

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes

import sqlalchemy as sa
from alembic import op
Comment on lines +9 to +10

# revision identifiers, used by Alembic.
revision = '1a31ce608336'
down_revision = 'd98dd8ec85a3'
revision = "1a31ce608336"
down_revision = "d98dd8ec85a3"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('item', 'owner_id',
existing_type=sa.UUID(),
nullable=False)
op.drop_constraint('item_owner_id_fkey', 'item', type_='foreignkey')
op.create_foreign_key(None, 'item', 'user', ['owner_id'], ['id'], ondelete='CASCADE')
op.alter_column("item", "owner_id", existing_type=sa.UUID(), nullable=False)
op.drop_constraint("item_owner_id_fkey", "item", type_="foreignkey")
op.create_foreign_key(
None, "item", "user", ["owner_id"], ["id"], ondelete="CASCADE"
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint('item_owner_id_fkey', 'item', type_='foreignkey')
op.create_foreign_key('item_owner_id_fkey', 'item', 'user', ['owner_id'], ['id'])
op.alter_column('item', 'owner_id',
existing_type=sa.UUID(),
nullable=True)
op.drop_constraint("item_owner_id_fkey", "item", type_="foreignkey")
op.create_foreign_key("item_owner_id_fkey", "item", "user", ["owner_id"], ["id"])
op.alter_column("item", "owner_id", existing_type=sa.UUID(), nullable=True)
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,88 @@
Create Date: 2024-06-17 14:42:44.639457

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes

import sqlalchemy as sa
from alembic import op
Comment on lines +9 to +10

# revision identifiers, used by Alembic.
revision = '9c0a54914c78'
down_revision = 'e2412789c190'
revision = "9c0a54914c78"
down_revision = "e2412789c190"
branch_labels = None
depends_on = None


def upgrade():
# Adjust the length of the email field in the User table
op.alter_column('user', 'email',
existing_type=sa.String(),
type_=sa.String(length=255),
existing_nullable=False)
op.alter_column(
"user",
"email",
existing_type=sa.String(),
type_=sa.String(length=255),
existing_nullable=False,
)

# Adjust the length of the full_name field in the User table
op.alter_column('user', 'full_name',
existing_type=sa.String(),
type_=sa.String(length=255),
existing_nullable=True)
op.alter_column(
"user",
"full_name",
existing_type=sa.String(),
type_=sa.String(length=255),
existing_nullable=True,
)

# Adjust the length of the title field in the Item table
op.alter_column('item', 'title',
existing_type=sa.String(),
type_=sa.String(length=255),
existing_nullable=False)
op.alter_column(
"item",
"title",
existing_type=sa.String(),
type_=sa.String(length=255),
existing_nullable=False,
)

# Adjust the length of the description field in the Item table
op.alter_column('item', 'description',
existing_type=sa.String(),
type_=sa.String(length=255),
existing_nullable=True)
op.alter_column(
"item",
"description",
existing_type=sa.String(),
type_=sa.String(length=255),
existing_nullable=True,
)


def downgrade():
# Revert the length of the email field in the User table
op.alter_column('user', 'email',
existing_type=sa.String(length=255),
type_=sa.String(),
existing_nullable=False)
op.alter_column(
"user",
"email",
existing_type=sa.String(length=255),
type_=sa.String(),
existing_nullable=False,
)

# Revert the length of the full_name field in the User table
op.alter_column('user', 'full_name',
existing_type=sa.String(length=255),
type_=sa.String(),
existing_nullable=True)
op.alter_column(
"user",
"full_name",
existing_type=sa.String(length=255),
type_=sa.String(),
existing_nullable=True,
)

# Revert the length of the title field in the Item table
op.alter_column('item', 'title',
existing_type=sa.String(length=255),
type_=sa.String(),
existing_nullable=False)
op.alter_column(
"item",
"title",
existing_type=sa.String(length=255),
type_=sa.String(),
existing_nullable=False,
)

# Revert the length of the description field in the Item table
op.alter_column('item', 'description',
existing_type=sa.String(length=255),
type_=sa.String(),
existing_nullable=True)
op.alter_column(
"item",
"description",
existing_type=sa.String(length=255),
type_=sa.String(),
existing_nullable=True,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
Create Date: 2024-07-19 04:08:04.000976

"""
from alembic import op

import sqlalchemy as sa
import sqlmodel.sql.sqltypes
from alembic import op
from sqlalchemy.dialects import postgresql
Comment on lines +8 to 11


# revision identifiers, used by Alembic.
revision = 'd98dd8ec85a3'
down_revision = '9c0a54914c78'
revision = "d98dd8ec85a3"
down_revision = "9c0a54914c78"
branch_labels = None
depends_on = None

Expand All @@ -23,68 +22,97 @@ def upgrade():
op.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"')

# Create a new UUID column with a default UUID value
op.add_column('user', sa.Column('new_id', postgresql.UUID(as_uuid=True), default=sa.text('uuid_generate_v4()')))
op.add_column('item', sa.Column('new_id', postgresql.UUID(as_uuid=True), default=sa.text('uuid_generate_v4()')))
op.add_column('item', sa.Column('new_owner_id', postgresql.UUID(as_uuid=True), nullable=True))
op.add_column(
"user",
sa.Column(
"new_id",
postgresql.UUID(as_uuid=True),
default=sa.text("uuid_generate_v4()"),
),
)
op.add_column(
"item",
sa.Column(
"new_id",
postgresql.UUID(as_uuid=True),
default=sa.text("uuid_generate_v4()"),
),
)
op.add_column(
"item", sa.Column("new_owner_id", postgresql.UUID(as_uuid=True), nullable=True)
)

# Populate the new columns with UUIDs
op.execute('UPDATE "user" SET new_id = uuid_generate_v4()')
op.execute('UPDATE item SET new_id = uuid_generate_v4()')
op.execute('UPDATE item SET new_owner_id = (SELECT new_id FROM "user" WHERE "user".id = item.owner_id)')
op.execute("UPDATE item SET new_id = uuid_generate_v4()")
op.execute(
'UPDATE item SET new_owner_id = (SELECT new_id FROM "user" WHERE "user".id = item.owner_id)'
)

# Set the new_id as not nullable
op.alter_column('user', 'new_id', nullable=False)
op.alter_column('item', 'new_id', nullable=False)
op.alter_column("user", "new_id", nullable=False)
op.alter_column("item", "new_id", nullable=False)

# Drop old columns and rename new columns
op.drop_constraint('item_owner_id_fkey', 'item', type_='foreignkey')
op.drop_column('item', 'owner_id')
op.alter_column('item', 'new_owner_id', new_column_name='owner_id')
op.drop_constraint("item_owner_id_fkey", "item", type_="foreignkey")
op.drop_column("item", "owner_id")
op.alter_column("item", "new_owner_id", new_column_name="owner_id")

op.drop_column('user', 'id')
op.alter_column('user', 'new_id', new_column_name='id')
op.drop_column("user", "id")
op.alter_column("user", "new_id", new_column_name="id")

op.drop_column('item', 'id')
op.alter_column('item', 'new_id', new_column_name='id')
op.drop_column("item", "id")
op.alter_column("item", "new_id", new_column_name="id")

# Create primary key constraint
op.create_primary_key('user_pkey', 'user', ['id'])
op.create_primary_key('item_pkey', 'item', ['id'])
op.create_primary_key("user_pkey", "user", ["id"])
op.create_primary_key("item_pkey", "item", ["id"])

# Recreate foreign key constraint
op.create_foreign_key('item_owner_id_fkey', 'item', 'user', ['owner_id'], ['id'])
op.create_foreign_key("item_owner_id_fkey", "item", "user", ["owner_id"], ["id"])


def downgrade():
# Reverse the upgrade process
op.add_column('user', sa.Column('old_id', sa.Integer, autoincrement=True))
op.add_column('item', sa.Column('old_id', sa.Integer, autoincrement=True))
op.add_column('item', sa.Column('old_owner_id', sa.Integer, nullable=True))
op.add_column("user", sa.Column("old_id", sa.Integer, autoincrement=True))
op.add_column("item", sa.Column("old_id", sa.Integer, autoincrement=True))
op.add_column("item", sa.Column("old_owner_id", sa.Integer, nullable=True))

# Populate the old columns with default values
# Generate sequences for the integer IDs if not exist
op.execute('CREATE SEQUENCE IF NOT EXISTS user_id_seq AS INTEGER OWNED BY "user".old_id')
op.execute('CREATE SEQUENCE IF NOT EXISTS item_id_seq AS INTEGER OWNED BY item.old_id')

op.execute('SELECT setval(\'user_id_seq\', COALESCE((SELECT MAX(old_id) + 1 FROM "user"), 1), false)')
op.execute('SELECT setval(\'item_id_seq\', COALESCE((SELECT MAX(old_id) + 1 FROM item), 1), false)')

op.execute('UPDATE "user" SET old_id = nextval(\'user_id_seq\')')
op.execute('UPDATE item SET old_id = nextval(\'item_id_seq\'), old_owner_id = (SELECT old_id FROM "user" WHERE "user".id = item.owner_id)')
op.execute(
'CREATE SEQUENCE IF NOT EXISTS user_id_seq AS INTEGER OWNED BY "user".old_id'
)
op.execute(
"CREATE SEQUENCE IF NOT EXISTS item_id_seq AS INTEGER OWNED BY item.old_id"
)

op.execute(
"SELECT setval('user_id_seq', COALESCE((SELECT MAX(old_id) + 1 FROM \"user\"), 1), false)"
)
op.execute(
"SELECT setval('item_id_seq', COALESCE((SELECT MAX(old_id) + 1 FROM item), 1), false)"
)

op.execute("UPDATE \"user\" SET old_id = nextval('user_id_seq')")
op.execute(
'UPDATE item SET old_id = nextval(\'item_id_seq\'), old_owner_id = (SELECT old_id FROM "user" WHERE "user".id = item.owner_id)'
)

# Drop new columns and rename old columns back
op.drop_constraint('item_owner_id_fkey', 'item', type_='foreignkey')
op.drop_column('item', 'owner_id')
op.alter_column('item', 'old_owner_id', new_column_name='owner_id')
op.drop_constraint("item_owner_id_fkey", "item", type_="foreignkey")
op.drop_column("item", "owner_id")
op.alter_column("item", "old_owner_id", new_column_name="owner_id")

op.drop_column('user', 'id')
op.alter_column('user', 'old_id', new_column_name='id')
op.drop_column("user", "id")
op.alter_column("user", "old_id", new_column_name="id")

op.drop_column('item', 'id')
op.alter_column('item', 'old_id', new_column_name='id')
op.drop_column("item", "id")
op.alter_column("item", "old_id", new_column_name="id")

# Create primary key constraint
op.create_primary_key('user_pkey', 'user', ['id'])
op.create_primary_key('item_pkey', 'item', ['id'])
op.create_primary_key("user_pkey", "user", ["id"])
op.create_primary_key("item_pkey", "item", ["id"])

# Recreate foreign key constraint
op.create_foreign_key('item_owner_id_fkey', 'item', 'user', ['owner_id'], ['id'])
op.create_foreign_key("item_owner_id_fkey", "item", "user", ["owner_id"], ["id"])
Loading
Loading