Coverage for src / local_deep_research / database / models / settings.py: 95%

55 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-14 23:55 +0000

1""" 

2Settings and configuration models. 

3Stores user preferences and API keys in encrypted database. 

4""" 

5 

6import enum 

7 

8from sqlalchemy import ( 

9 JSON, 

10 Boolean, 

11 Column, 

12 Enum, 

13 Float, 

14 Integer, 

15 String, 

16 Text, 

17) 

18from sqlalchemy_utc import UtcDateTime, utcnow 

19 

20from .base import Base 

21 

22 

23class UserSettings(Base): 

24 """ 

25 User-specific settings stored in their encrypted database. 

26 Replaces the need for config files or unencrypted storage. 

27 """ 

28 

29 __tablename__ = "user_settings" 

30 

31 id = Column(Integer, primary_key=True) 

32 key = Column(String(255), unique=True, nullable=False, index=True) 

33 value = Column(JSON) 

34 category = Column(String(100)) 

35 description = Column(Text) 

36 created_at = Column(UtcDateTime, default=utcnow()) 

37 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow()) 

38 

39 def __repr__(self): 

40 return f"<UserSettings(key='{self.key}', category='{self.category}')>" 

41 

42 

43class APIKey(Base): 

44 """ 

45 Encrypted storage for API keys. 

46 These are especially sensitive and benefit from database encryption. 

47 """ 

48 

49 __tablename__ = "api_keys" 

50 

51 id = Column(Integer, primary_key=True) 

52 provider = Column(String(100), unique=True, nullable=False, index=True) 

53 key = Column(Text, nullable=False) # Encrypted by SQLCipher 

54 description = Column(Text) 

55 is_active = Column(Boolean, default=True) 

56 created_at = Column(UtcDateTime, default=utcnow()) 

57 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow()) 

58 last_used = Column(UtcDateTime) 

59 usage_count = Column(Integer, default=0) 

60 

61 def __repr__(self): 

62 # Never show the actual key in repr 

63 return f"<APIKey(provider='{self.provider}', active={self.is_active})>" 

64 

65 

66class SettingType(str, enum.Enum): 

67 """Types of settings. 

68 

69 Inherits from ``str`` so that instances are JSON-serializable and work 

70 seamlessly with both SQLAlchemy columns and Pydantic models. 

71 """ 

72 

73 APP = "app" 

74 LLM = "llm" 

75 SEARCH = "search" 

76 REPORT = "report" 

77 DATABASE = "database" 

78 

79 

80class Setting(Base): 

81 """ 

82 Global application settings (shared across users). 

83 For user-specific settings, use UserSettings. 

84 """ 

85 

86 __tablename__ = "settings" 

87 

88 id = Column(Integer, primary_key=True, index=True) 

89 key = Column(String(255), nullable=False, unique=True, index=True) 

90 value = Column(JSON, nullable=True) 

91 type = Column(Enum(SettingType), nullable=False, index=True) 

92 name = Column(String(255), nullable=False) 

93 description = Column(Text, nullable=True) 

94 category = Column(String(100), nullable=True, index=True) 

95 ui_element = Column(String(50), default="text", nullable=False) 

96 options = Column(JSON, nullable=True) # For select elements 

97 min_value = Column(Float, nullable=True) # For numeric inputs 

98 max_value = Column(Float, nullable=True) # For numeric inputs 

99 step = Column(Float, nullable=True) # For sliders 

100 visible = Column(Boolean, default=True, nullable=False) 

101 editable = Column(Boolean, default=True, nullable=False) 

102 env_var = Column(String(255), nullable=True) # Environment variable name 

103 created_at = Column(UtcDateTime, server_default=utcnow(), nullable=False) 

104 updated_at = Column( 

105 UtcDateTime, server_default=utcnow(), onupdate=utcnow(), nullable=False 

106 ) 

107 

108 # unique=True on the key column already creates a unique constraint; 

109 # the separate UniqueConstraint was removed to avoid Alembic autogenerate drift. 

110 

111 def __repr__(self): 

112 return f"<Setting(key='{self.key}', type={self.type.value})>"