Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 4 additions & 2 deletions .github/workflows/migrate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ jobs:
name: Migrate development database
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
environment: development
env:
DB_URL: ${{ secrets.DB_URL_DEV }}
DB_URL: ${{ secrets.DB_URL }}

steps:
- uses: actions/checkout@v4
Expand All @@ -39,8 +40,9 @@ jobs:
name: Migrate production database
if: github.event_name == 'push'
runs-on: ubuntu-latest
environment: production
env:
DB_URL: ${{ secrets.DB_URL_PROD }}
DB_URL: ${{ secrets.DB_URL }}

steps:
- uses: actions/checkout@v4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""add_linked_object_type_to_task_template

Revision ID: a2f968506210
Revises: b3c4d5e6f7a8
Create Date: 2026-02-22 15:09:29.195456

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = 'a2f968506210'
down_revision: Union[str, Sequence[str], None] = 'b3c4d5e6f7a8'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
"""Upgrade schema."""
op.add_column('task_template', sa.Column('linked_object_type', sa.Enum('CLIENT', 'ORDER', 'RECURRING_ORDER', name='tasklinkedobjecttype'), nullable=True))


def downgrade() -> None:
"""Downgrade schema."""
op.drop_column('task_template', 'linked_object_type')
22 changes: 11 additions & 11 deletions database_utils/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
# Load environment variables
load_dotenv()

# Get the database credentials from environment variables
db_user = os.getenv("POSTGRES_USER")
db_password = os.getenv("POSTGRES_PASSWORD")
db_host = os.getenv("POSTGRES_HOST")
db_port = os.getenv("POSTGRES_PORT")
db_name = os.getenv("POSTGRES_DB")
# Accept either a full connection URL or individual POSTGRES_* components
DATABASE_URL = os.getenv("DATABASE_URL") or os.getenv("DB_URL")
if not DATABASE_URL:
db_user = os.getenv("POSTGRES_USER")
db_password = os.getenv("POSTGRES_PASSWORD")
db_host = os.getenv("POSTGRES_HOST")
db_port = os.getenv("POSTGRES_PORT")
db_name = os.getenv("POSTGRES_DB")

# Ensure all required variables are present
if not all([db_user, db_password, db_host, db_port, db_name]):
raise ValueError("Missing required database configuration. Please check your environment variables.")
if not all([db_user, db_password, db_host, db_port, db_name]):
raise ValueError("Missing required database configuration. Please check your environment variables.")

# Construct the PostgreSQL connection URL
DATABASE_URL = f"postgresql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}"
DATABASE_URL = f"postgresql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}"

# Create engine with explicit configurations
engine = create_engine(
Expand Down
1 change: 1 addition & 0 deletions database_utils/models/crm.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ class TaskTemplate(Base):
description = Column(String, nullable=True)
due_date_offset_days = Column(Integer, nullable=True)
default_assignee_ids = Column(JSON, nullable=True)
linked_object_type = Column(Enum(TaskLinkedObjectType), nullable=True)

company_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("company.id", ondelete="CASCADE"), nullable=False)
created_by: Mapped[uuid.UUID | None] = mapped_column(Uuid, ForeignKey("user.id", ondelete="SET NULL"), nullable=True)
Expand Down
4 changes: 3 additions & 1 deletion database_utils/schemas/task_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from uuid import UUID
from datetime import datetime

from .task import TaskAssigneeSimple
from .task import TaskAssigneeSimple, TaskLinkedObjectType


class TaskTemplateBase(BaseModel):
Expand All @@ -12,6 +12,7 @@ class TaskTemplateBase(BaseModel):
description: Optional[str] = None
due_date_offset_days: Optional[int] = None
default_assignee_ids: Optional[List[UUID]] = None
linked_object_type: Optional[TaskLinkedObjectType] = None


class TaskTemplateCreate(TaskTemplateBase):
Expand All @@ -24,6 +25,7 @@ class TaskTemplateUpdate(BaseModel):
description: Optional[str] = None
due_date_offset_days: Optional[int] = None
default_assignee_ids: Optional[List[UUID]] = None
linked_object_type: Optional[TaskLinkedObjectType] = None


class TaskTemplateOut(TaskTemplateBase):
Expand Down
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = database-utils
version = 1.4.3
version = 1.4.4
author = Ricardo Pellecer
author_email = you@example.com
description = Shared SQLAlchemy models, migrations, and dependencies for FastAPI services with comprehensive audit logging (UUID primary keys)
Expand All @@ -25,6 +25,7 @@ install_requires =
PyJWT>=2.8.0
loguru>=0.7.3
email-validator>=2.0.0
opentelemetry-api>=1.20.0

[options.packages.find]
include = database_utils*