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
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""Fixing inconsistencies
Revision ID: 4aa1f48c6321
Revises: 3389c67fdcb4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix revision ID inconsistency.

The revision ID in the docstring (line 4) shows 4aa1f48c6321 but the down_revision (line 15) shows f2589428c1d0, which doesn't match the revision ID from line 4. This creates confusion about the migration chain.

Verify the correct down_revision value and update accordingly:

-down_revision = "f2589428c1d0"
+down_revision = "3389c67fdcb4"

Also applies to: 15-15

🤖 Prompt for AI Agents
In backend/app/alembic/versions/4aa1f48c6321_add_inconistency_fixes.py at line 4
and line 15, the revision ID in the docstring does not match the down_revision
value, causing confusion in the migration chain. Verify the correct
down_revision value that corresponds to this migration and update the
down_revision variable at line 15 to match the correct previous revision ID.

Create Date: 2025-07-03 16:46:13.642386
"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = "4aa1f48c6321"
down_revision = "f2589428c1d0"
branch_labels = None
depends_on = None


def upgrade():
op.alter_column(
"collection", "project_id", existing_type=sa.INTEGER(), nullable=False
)
op.alter_column(
"credential",
"inserted_at",
existing_type=postgresql.TIMESTAMP(),
nullable=False,
)
op.alter_column(
"credential", "updated_at", existing_type=postgresql.TIMESTAMP(), nullable=False
)
op.alter_column(
"credential", "project_id", existing_type=sa.INTEGER(), nullable=False
)
op.create_index(
op.f("ix_openai_assistant_assistant_id"),
"openai_assistant",
["assistant_id"],
unique=True,
)
op.drop_constraint("project_organization_id_fkey", "project", type_="foreignkey")
op.create_foreign_key(
None, "project", "organization", ["organization_id"], ["id"], ondelete="CASCADE"
)
op.drop_constraint("credential_project_id_fkey", "credential", type_="foreignkey")
op.create_foreign_key(
None, "credential", "project", ["project_id"], ["id"], ondelete="CASCADE"
)


def downgrade():
op.drop_constraint(None, "project", type_="foreignkey")
op.create_foreign_key(
"project_organization_id_fkey",
"project",
"organization",
["organization_id"],
["id"],
)
op.drop_index(
op.f("ix_openai_assistant_assistant_id"), table_name="openai_assistant"
)
op.drop_constraint(None, "credential", type_="foreignkey")
op.create_foreign_key(
"credential_project_id_fkey",
"credential",
"project",
["project_id"],
["id"],
ondelete="SET NULL",
)
op.alter_column(
"credential", "updated_at", existing_type=postgresql.TIMESTAMP(), nullable=True
)
op.alter_column(
"credential", "inserted_at", existing_type=postgresql.TIMESTAMP(), nullable=True
)
op.alter_column(
"collection", "project_id", existing_type=sa.INTEGER(), nullable=True
)
op.alter_column(
"credential", "project_id", existing_type=sa.INTEGER(), nullable=True
)
12 changes: 8 additions & 4 deletions backend/app/models/assistants.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from datetime import datetime
from typing import Optional, List
from sqlmodel import Field, Relationship, SQLModel
from sqlalchemy import Column, String
from sqlalchemy import Column, String, Text
from sqlalchemy.dialects.postgresql import ARRAY

from app.core.util import now
Expand All @@ -10,15 +10,19 @@
class AssistantBase(SQLModel):
assistant_id: str = Field(index=True, unique=True)
name: str
instructions: str
instructions: str = Field(sa_column=Column(Text, nullable=False))
model: str
vector_store_ids: List[str] = Field(
default_factory=list, sa_column=Column(ARRAY(String))
)
temperature: float = 0.1
max_num_results: int = 20
project_id: int = Field(foreign_key="project.id")
organization_id: int = Field(foreign_key="organization.id")
project_id: int = Field(
foreign_key="project.id", nullable=False, ondelete="CASCADE"
)
organization_id: int = Field(
foreign_key="organization.id", nullable=False, ondelete="CASCADE"
)


class Assistant(AssistantBase, table=True):
Expand Down
2 changes: 1 addition & 1 deletion backend/app/models/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Collection(SQLModel, table=True):

project_id: int = Field(
foreign_key="project.id",
nullable=True,
nullable=False,
ondelete="CASCADE",
)

Expand Down
14 changes: 9 additions & 5 deletions backend/app/models/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@


class CredsBase(SQLModel):
organization_id: int = Field(foreign_key="organization.id")
project_id: Optional[int] = Field(default=None, foreign_key="project.id")
organization_id: int = Field(
foreign_key="organization.id", nullable=False, ondelete="CASCADE"
)
project_id: int = Field(
default=None, foreign_key="project.id", nullable=False, ondelete="CASCADE"
)
is_active: bool = True


Expand Down Expand Up @@ -53,16 +57,16 @@ class Credential(CredsBase, table=True):
index=True, description="Provider name like 'openai', 'gemini'"
)
credential: str = Field(
sa_column=sa.Column(sa.String),
sa_column=sa.Column(sa.String, nullable=False),
description="Encrypted provider-specific credentials",
)
inserted_at: datetime = Field(
default_factory=now,
sa_column=sa.Column(sa.DateTime, default=datetime.utcnow),
sa_column=sa.Column(sa.DateTime, default=datetime.utcnow, nullable=False),
)
updated_at: datetime = Field(
default_factory=now,
sa_column=sa.Column(sa.DateTime, onupdate=datetime.utcnow),
sa_column=sa.Column(sa.DateTime, onupdate=datetime.utcnow, nullable=False),
)
deleted_at: Optional[datetime] = Field(
default=None, sa_column=sa.Column(sa.DateTime, nullable=True)
Expand Down
10 changes: 5 additions & 5 deletions backend/app/models/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ class Organization(OrganizationBase, table=True):

# Relationship back to Creds
api_keys: list["APIKey"] = Relationship(
back_populates="organization", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="organization", cascade_delete=True
)
creds: list["Credential"] = Relationship(
back_populates="organization", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="organization", cascade_delete=True
)
project: list["Project"] = Relationship(
back_populates="organization", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="organization", cascade_delete=True
)
assistants: list["Assistant"] = Relationship(
back_populates="organization", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="organization", cascade_delete=True
)
collections: list["Collection"] = Relationship(
back_populates="organization", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="organization", cascade_delete=True
)


Expand Down
12 changes: 7 additions & 5 deletions backend/app/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,27 @@ class ProjectUpdate(SQLModel):
# Database model for Project
class Project(ProjectBase, table=True):
id: int = Field(default=None, primary_key=True)
organization_id: int = Field(foreign_key="organization.id", index=True)
organization_id: int = Field(
foreign_key="organization.id", index=True, nullable=False, ondelete="CASCADE"
)
inserted_at: datetime = Field(default_factory=now, nullable=False)
updated_at: datetime = Field(default_factory=now, nullable=False)

users: list["ProjectUser"] = Relationship(
back_populates="project", cascade_delete=True
)
creds: list["Credential"] = Relationship(
back_populates="project", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="project", cascade_delete=True
)
assistants: list["Assistant"] = Relationship(
back_populates="project", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="project", cascade_delete=True
)
api_keys: list["APIKey"] = Relationship(
back_populates="project", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="project", cascade_delete=True
)
organization: Optional["Organization"] = Relationship(back_populates="project")
collections: list["Collection"] = Relationship(
back_populates="project", sa_relationship_kwargs={"cascade": "all, delete"}
back_populates="project", cascade_delete=True
)


Expand Down
2 changes: 1 addition & 1 deletion backend/app/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class User(UserBase, table=True):
projects: list["ProjectUser"] = Relationship(
back_populates="user", cascade_delete=True
)
api_keys: list["APIKey"] = Relationship(back_populates="user")
api_keys: list["APIKey"] = Relationship(back_populates="user", cascade_delete=True)


class UserOrganization(UserBase):
Expand Down
13 changes: 8 additions & 5 deletions backend/app/tests/api/routes/test_creds.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def test_set_credential(db: Session, superuser_token_headers: dict[str, str]):
data = response.json()["data"]
assert isinstance(data, list)
assert len(data) == 1

assert data[0]["organization_id"] == project.organization_id
assert data[0]["provider"] == Provider.OPENAI.value
assert data[0]["credential"]["model"] == "gpt-4"
Expand All @@ -70,7 +71,7 @@ def test_set_credentials_for_invalid_project_org_relationship(
credential_data_invalid = {
"organization_id": org1.id,
"is_active": True,
"project_id": project2.id, # Invalid project for org1
"project_id": project2.id,
"credential": {Provider.OPENAI.value: {"api_key": "sk-123", "model": "gpt-4"}},
}

Expand Down Expand Up @@ -389,11 +390,12 @@ def test_duplicate_credential_creation(
def test_multiple_provider_credentials(
db: Session, superuser_token_headers: dict[str, str]
):
org = create_test_organization(db)
project = create_test_project(db)

# Create OpenAI credentials
openai_credential = {
"organization_id": org.id,
"organization_id": project.organization_id,
"project_id": project.id,
"is_active": True,
"credential": {
Provider.OPENAI.value: {
Expand All @@ -406,7 +408,8 @@ def test_multiple_provider_credentials(

# Create Langfuse credentials
langfuse_credential = {
"organization_id": org.id,
"organization_id": project.organization_id,
"project_id": project.id,
"is_active": True,
"credential": {
Provider.LANGFUSE.value: {
Expand Down Expand Up @@ -434,7 +437,7 @@ def test_multiple_provider_credentials(

# Fetch all credentials
response = client.get(
f"{settings.API_V1_STR}/credentials/{org.id}",
f"{settings.API_V1_STR}/credentials/{project.organization_id}",
headers=superuser_token_headers,
)
assert response.status_code == 200
Expand Down
9 changes: 4 additions & 5 deletions backend/app/tests/crud/test_credentials.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sqlmodel import Session
import pytest
from sqlmodel import Session

from app.crud import (
set_creds_for_org,
Expand Down Expand Up @@ -31,7 +31,6 @@ def test_set_credentials_for_org(db: Session) -> None:
"host": "https://cloud.langfuse.com",
},
}

credentials_create = CredsCreate(
organization_id=project.organization_id,
project_id=project.id,
Expand Down Expand Up @@ -109,7 +108,9 @@ def test_update_creds_for_org(db: Session) -> None:
)
# Update credentials
updated_creds = {"api_key": "updated-key"}
creds_update = CredsUpdate(provider="openai", credential=updated_creds)
creds_update = CredsUpdate(
project_id=project.id, provider="openai", credential=updated_creds
)

updated = update_creds_for_org(
session=db, org_id=credential.organization_id, creds_in=creds_update
Expand Down Expand Up @@ -189,7 +190,6 @@ def test_invalid_provider(db: Session) -> None:

# Test with unsupported provider
credentials_data = {"gemini": {"api_key": "test-key"}}

credentials_create = CredsCreate(
organization_id=project.organization_id,
project_id=project.id,
Expand Down Expand Up @@ -235,7 +235,6 @@ def test_langfuse_credential_validation(db: Session) -> None:
# Missing host
}
}

credentials_create = CredsCreate(
organization_id=project.organization_id,
project_id=project.id,
Expand Down