File size: 5,570 Bytes
f9474bf 7657e9f f9474bf 1bd1322 f9474bf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | import os
from datetime import datetime
from uuid import uuid4
from sqlalchemy import create_engine, Column, String, Boolean, DateTime, Text, Integer, ForeignKey, JSON
from sqlalchemy.orm import declarative_base, sessionmaker, relationship
from passlib.context import CryptContext
Base = declarative_base()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
DATABASE_PATH = os.environ.get("DATA_DIR", "/data") + "/platform.db"
engine = create_engine(f"sqlite:///{DATABASE_PATH}", connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
class User(Base):
__tablename__ = "users"
id = Column(String, primary_key=True, default=lambda: str(uuid4()))
email = Column(String, unique=True, nullable=False)
hashed_password = Column(String, nullable=False)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
api_keys = relationship("APIKey", back_populates="user", cascade="all, delete-orphan")
connections = relationship("Connection", back_populates="user", cascade="all, delete-orphan")
class APIKey(Base):
__tablename__ = "api_keys"
id = Column(String, primary_key=True, default=lambda: str(uuid4()))
user_id = Column(String, ForeignKey("users.id"), nullable=False)
key_hash = Column(String, nullable=False, index=True)
name = Column(String, nullable=False)
last_used = Column(DateTime, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
is_active = Column(Boolean, default=True)
user = relationship("User", back_populates="api_keys")
class Integration(Base):
__tablename__ = "integrations"
id = Column(String, primary_key=True)
name = Column(String, nullable=False)
description = Column(String, nullable=False)
logo_url = Column(String, nullable=False)
category = Column(String, nullable=False)
auth_type = Column(String, nullable=False)
oauth_scopes = Column(JSON, nullable=True)
is_active = Column(Boolean, default=True)
tool_count = Column(Integer, default=0)
trigger_count = Column(Integer, default=0)
tools = relationship("Tool", back_populates="integration", cascade="all, delete-orphan")
class AuthConfig(Base):
"""Dynamic credential schema per integration - defines what fields are needed."""
__tablename__ = "auth_configs"
id = Column(String, primary_key=True, default=lambda: str(uuid4()))
integration_id = Column(String, ForeignKey("integrations.id"), nullable=False)
auth_type = Column(String, nullable=False) # oauth2, api_key, bearer, basic
fields = Column(JSON, nullable=False) # [{name, label, type, required, description, default}]
oauth_authorize_url = Column(String, nullable=True)
oauth_token_url = Column(String, nullable=True)
is_active = Column(Boolean, default=True)
integration = relationship("Integration")
class Connection(Base):
__tablename__ = "connections"
id = Column(String, primary_key=True, default=lambda: str(uuid4()))
user_id = Column(String, ForeignKey("users.id"), nullable=False)
integration_id = Column(String, ForeignKey("integrations.id"), nullable=False)
account_label = Column(String, nullable=True)
status = Column(String, default="active")
encrypted_credentials = Column(Text, nullable=False)
connected_at = Column(DateTime, default=datetime.utcnow)
last_used = Column(DateTime, nullable=True)
conn_metadata = Column("metadata", JSON, nullable=True)
user = relationship("User", back_populates="connections")
integration = relationship("Integration")
class Tool(Base):
__tablename__ = "tools"
id = Column(String, primary_key=True)
integration_id = Column(String, ForeignKey("integrations.id"), nullable=False)
name = Column(String, nullable=False)
description = Column(String, nullable=False)
input_schema = Column(JSON, nullable=False)
output_schema = Column(JSON, nullable=True)
category = Column(String, nullable=True)
is_active = Column(Boolean, default=True)
integration = relationship("Integration", back_populates="tools")
class ToolExecution(Base):
__tablename__ = "tool_executions"
id = Column(String, primary_key=True, default=lambda: str(uuid4()))
user_id = Column(String, ForeignKey("users.id"), nullable=False)
tool_id = Column(String, ForeignKey("tools.id"), nullable=False)
connection_id = Column(String, ForeignKey("connections.id"), nullable=True)
input_params = Column(JSON, nullable=True)
output_result = Column(JSON, nullable=True)
status = Column(String, default="success")
latency_ms = Column(Integer, default=0)
error_message = Column(Text, nullable=True)
executed_at = Column(DateTime, default=datetime.utcnow)
source = Column(String, default="api")
user = relationship("User")
tool = relationship("Tool")
connection = relationship("Connection")
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def init_db():
Base.metadata.create_all(bind=engine)
db = SessionLocal()
try:
existing = db.query(User).filter(User.email == "admin@platform.local").first()
if not existing:
admin = User(
id=str(uuid4()),
email="admin@platform.local",
hashed_password=pwd_context.hash("admin123"),
is_active=True
)
db.add(admin)
db.commit()
finally:
db.close() |