Files
matteoscrugli 8c4a555b88 Add comprehensive backend features and mobile UI improvements
Backend:
- Add 2FA authentication with TOTP support
- Add API keys management system
- Add audit logging for security events
- Add file upload/management system
- Add notifications system with preferences
- Add session management
- Add webhooks integration
- Add analytics endpoints
- Add export functionality
- Add password policy enforcement
- Add new database migrations for core tables

Frontend:
- Add module position system (top/bottom sidebar sections)
- Add search and notifications module configuration tabs
- Add mobile logo replacing hamburger menu
- Center page title absolutely when no tabs present
- Align sidebar footer toggles with navigation items
- Add lighter icon color in dark theme for mobile
- Add API keys management page
- Add notifications page with context
- Add admin analytics and audit logs pages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 22:27:32 +01:00

77 lines
2.7 KiB
Python

"""User database model."""
import json
import uuid
from sqlalchemy import Column, String, Boolean, Text
from sqlalchemy.sql import func
from sqlalchemy.types import DateTime
from app.db.base import Base
class User(Base):
"""User model for authentication and authorization."""
__tablename__ = "users"
# Using String(36) for UUID to support SQLite
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
username = Column(String(100), unique=True, nullable=False, index=True)
email = Column(String(255), unique=True, nullable=False, index=True)
hashed_password = Column(String(255), nullable=False)
is_active = Column(Boolean, default=True, nullable=False)
is_superuser = Column(Boolean, default=False, nullable=False)
# User permissions for modules (JSON stored as text for SQLite compatibility)
# Format: {"playlists": true, "downloads": false, "chromecast": true}
# null means inherit from global settings (all enabled by default)
_permissions = Column("permissions", Text, nullable=True)
# 2FA fields
totp_secret = Column(String(32), nullable=True) # Base32 encoded TOTP secret
totp_enabled = Column(Boolean, default=False, nullable=False)
totp_backup_codes = Column(Text, nullable=True) # JSON array of backup codes
created_at = Column(DateTime, server_default=func.now(), nullable=False)
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False)
last_login = Column(DateTime, nullable=True)
@property
def permissions(self) -> dict:
"""Get permissions as a dictionary."""
if self._permissions:
try:
return json.loads(self._permissions)
except json.JSONDecodeError:
return {}
return {}
@permissions.setter
def permissions(self, value: dict):
"""Set permissions from a dictionary."""
if value is None:
self._permissions = None
else:
self._permissions = json.dumps(value)
@property
def backup_codes(self) -> list:
"""Get backup codes as a list."""
if self.totp_backup_codes:
try:
return json.loads(self.totp_backup_codes)
except json.JSONDecodeError:
return []
return []
@backup_codes.setter
def backup_codes(self, value: list):
"""Set backup codes from a list."""
if value is None:
self.totp_backup_codes = None
else:
self.totp_backup_codes = json.dumps(value)
def __repr__(self):
return f"<User(id={self.id}, username='{self.username}', email='{self.email}')>"