mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-31 09:06:52 +09:00
Comments, docstrings and a few strings cited plan numbers ("plan 29
#9", "plan 86 §B2") from a git-ignored folder, so they pointed at
nothing; one reached users in a bottleneck hint. Code and frontend
strings are unchanged apart from those citations (checked by AST and
token comparison). A vhost still carrying the old asset comment reads
as undrifted, and a guard test keeps new citations out.
83 lines
3.1 KiB
Python
83 lines
3.1 KiB
Python
from datetime import datetime
|
|
from app import db
|
|
from app.models.json_column_mixin import JsonColumnMixin
|
|
|
|
|
|
class SystemSettings(JsonColumnMixin, db.Model):
|
|
"""Key-value store for system-wide settings."""
|
|
__tablename__ = 'system_settings'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
key = db.Column(db.String(100), unique=True, nullable=False, index=True)
|
|
value = db.Column(db.Text, nullable=True)
|
|
value_type = db.Column(db.String(20), default='string') # string, boolean, integer, json
|
|
description = db.Column(db.String(500), nullable=True)
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
updated_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True, index=True)
|
|
|
|
# Relationship to user who last updated
|
|
updated_by_user = db.relationship('User', foreign_keys=[updated_by])
|
|
|
|
def get_typed_value(self):
|
|
"""Return the value converted to its appropriate type."""
|
|
if self.value is None:
|
|
return None
|
|
if self.value_type == 'boolean':
|
|
return self.value.lower() in ('true', '1', 'yes')
|
|
if self.value_type == 'integer':
|
|
return int(self.value)
|
|
if self.value_type == 'json':
|
|
# Corrupt JSON degrades to None instead of raising.
|
|
return self._json_read('value', None)
|
|
return self.value
|
|
|
|
def set_typed_value(self, value):
|
|
"""Set the value, converting from its type to string storage."""
|
|
if value is None:
|
|
self.value = None
|
|
elif self.value_type == 'boolean':
|
|
self.value = 'true' if value else 'false'
|
|
elif self.value_type == 'integer':
|
|
self.value = str(int(value))
|
|
elif self.value_type == 'json':
|
|
import json
|
|
self.value = json.dumps(value)
|
|
else:
|
|
self.value = str(value)
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'id': self.id,
|
|
'key': self.key,
|
|
'value': self.get_typed_value(),
|
|
'value_type': self.value_type,
|
|
'description': self.description,
|
|
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
|
|
'updated_by': self.updated_by
|
|
}
|
|
|
|
@staticmethod
|
|
def get(key, default=None):
|
|
"""Get a setting value by key."""
|
|
setting = SystemSettings.query.filter_by(key=key).first()
|
|
if setting:
|
|
return setting.get_typed_value()
|
|
return default
|
|
|
|
@staticmethod
|
|
def set(key, value, value_type='string', description=None, user_id=None):
|
|
"""Set a setting value by key."""
|
|
setting = SystemSettings.query.filter_by(key=key).first()
|
|
if not setting:
|
|
setting = SystemSettings(key=key, value_type=value_type, description=description)
|
|
db.session.add(setting)
|
|
setting.set_typed_value(value)
|
|
if description is not None:
|
|
setting.description = description
|
|
if user_id is not None:
|
|
setting.updated_by = user_id
|
|
return setting
|
|
|
|
def __repr__(self):
|
|
return f'<SystemSettings {self.key}={self.value}>'
|