Coverage for src / local_deep_research / database / models / settings.py: 95%
56 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
1"""
2Settings and configuration models.
3Stores user preferences and API keys in encrypted database.
4"""
6import enum
8from sqlalchemy import (
9 JSON,
10 Boolean,
11 Column,
12 Enum,
13 Float,
14 Integer,
15 String,
16 Text,
17 UniqueConstraint,
18)
19from sqlalchemy_utc import UtcDateTime, utcnow
21from .base import Base
24class UserSettings(Base):
25 """
26 User-specific settings stored in their encrypted database.
27 Replaces the need for config files or unencrypted storage.
28 """
30 __tablename__ = "user_settings"
32 id = Column(Integer, primary_key=True)
33 key = Column(String(255), unique=True, nullable=False, index=True)
34 value = Column(JSON)
35 category = Column(String(100))
36 description = Column(Text)
37 created_at = Column(UtcDateTime, default=utcnow())
38 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow())
40 def __repr__(self):
41 return f"<UserSettings(key='{self.key}', category='{self.category}')>"
44class APIKey(Base):
45 """
46 Encrypted storage for API keys.
47 These are especially sensitive and benefit from database encryption.
48 """
50 __tablename__ = "api_keys"
52 id = Column(Integer, primary_key=True)
53 provider = Column(String(100), unique=True, nullable=False, index=True)
54 key = Column(Text, nullable=False) # Encrypted by SQLCipher
55 description = Column(Text)
56 is_active = Column(Boolean, default=True)
57 created_at = Column(UtcDateTime, default=utcnow())
58 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow())
59 last_used = Column(UtcDateTime)
60 usage_count = Column(Integer, default=0)
62 def __repr__(self):
63 # Never show the actual key in repr
64 return f"<APIKey(provider='{self.provider}', active={self.is_active})>"
67class SettingType(enum.Enum):
68 """Types of settings."""
70 APP = "app"
71 LLM = "llm"
72 SEARCH = "search"
73 REPORT = "report"
74 DATABASE = "database"
77class Setting(Base):
78 """
79 Global application settings (shared across users).
80 For user-specific settings, use UserSettings.
81 """
83 __tablename__ = "settings"
85 id = Column(Integer, primary_key=True, index=True)
86 key = Column(String(255), nullable=False, unique=True, index=True)
87 value = Column(JSON, nullable=True)
88 type = Column(Enum(SettingType), nullable=False, index=True)
89 name = Column(String(255), nullable=False)
90 description = Column(Text, nullable=True)
91 category = Column(String(100), nullable=True, index=True)
92 ui_element = Column(String(50), default="text", nullable=False)
93 options = Column(JSON, nullable=True) # For select elements
94 min_value = Column(Float, nullable=True) # For numeric inputs
95 max_value = Column(Float, nullable=True) # For numeric inputs
96 step = Column(Float, nullable=True) # For sliders
97 visible = Column(Boolean, default=True, nullable=False)
98 editable = Column(Boolean, default=True, nullable=False)
99 env_var = Column(String(255), nullable=True) # Environment variable name
100 created_at = Column(UtcDateTime, server_default=utcnow(), nullable=False)
101 updated_at = Column(
102 UtcDateTime, server_default=utcnow(), onupdate=utcnow(), nullable=False
103 )
105 __table_args__ = (UniqueConstraint("key", name="uix_settings_key"),)
107 def __repr__(self):
108 return f"<Setting(key='{self.key}', type={self.type.value})>"