Merge website-branding feature and adjust for compatibility

- Resolved conflicts in models.py, app.py, and template files
- Added branding checks to prevent errors when g.branding is None
- Updated all template references to use conditional branding
- Added BrandingSettings to migrations
- Created branding uploads directory
- Integrated branding with existing comment and task management features
This commit is contained in:
2025-07-06 16:58:29 +02:00
14 changed files with 466 additions and 35 deletions

View File

@@ -195,16 +195,18 @@ class User(db.Model):
import pyotp
self.two_factor_secret = pyotp.random_base32()
return self.two_factor_secret
def get_2fa_uri(self):
def get_2fa_uri(self, issuer_name=None):
"""Get the provisioning URI for QR code generation"""
if not self.two_factor_secret:
return None
import pyotp
totp = pyotp.TOTP(self.two_factor_secret)
if issuer_name is None:
issuer_name = "Time Tracker" # Default fallback
return totp.provisioning_uri(
name=self.email,
issuer_name="TimeTrack"
issuer_name=issuer_name
)
def verify_2fa_token(self, token, allow_setup=False):
@@ -267,6 +269,38 @@ class SystemSettings(db.Model):
def __repr__(self):
return f'<SystemSettings {self.key}={self.value}>'
class BrandingSettings(db.Model):
id = db.Column(db.Integer, primary_key=True)
app_name = db.Column(db.String(100), nullable=False, default='Time Tracker')
logo_filename = db.Column(db.String(255), nullable=True) # Filename of uploaded logo
logo_alt_text = db.Column(db.String(255), nullable=True, default='Logo')
favicon_filename = db.Column(db.String(255), nullable=True) # Filename of uploaded favicon
primary_color = db.Column(db.String(7), nullable=True, default='#007bff') # Hex color
# Meta fields
created_at = db.Column(db.DateTime, default=datetime.now)
updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)
updated_by_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)
# Relationships
updated_by = db.relationship('User', foreign_keys=[updated_by_id])
def __repr__(self):
return f'<BrandingSettings {self.app_name}>'
@staticmethod
def get_current():
"""Get current branding settings or create defaults"""
settings = BrandingSettings.query.first()
if not settings:
settings = BrandingSettings(
app_name='Time Tracker',
logo_alt_text='Application Logo'
)
db.session.add(settings)
db.session.commit()
return settings
class TimeEntry(db.Model):
id = db.Column(db.Integer, primary_key=True)
arrival_time = db.Column(db.DateTime, nullable=False)