Initial commit
This commit is contained in:
commit
983cee0320
322 changed files with 57174 additions and 0 deletions
71
backup/first -fina app/app/models/user.py
Executable file
71
backup/first -fina app/app/models/user.py
Executable file
|
|
@ -0,0 +1,71 @@
|
|||
from flask_login import UserMixin
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from app import db
|
||||
from datetime import datetime
|
||||
import pyotp
|
||||
|
||||
class User(UserMixin, db.Model):
|
||||
__tablename__ = 'users'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(80), unique=True, nullable=False)
|
||||
email = db.Column(db.String(120), unique=True, nullable=False)
|
||||
password_hash = db.Column(db.String(200), nullable=False)
|
||||
is_admin = db.Column(db.Boolean, default=False)
|
||||
currency = db.Column(db.String(3), default='USD')
|
||||
language = db.Column(db.String(2), default='en') # en, ro, es
|
||||
|
||||
# Budget alert preferences
|
||||
budget_alerts_enabled = db.Column(db.Boolean, default=True)
|
||||
alert_email = db.Column(db.String(120), nullable=True) # Optional separate alert email
|
||||
|
||||
# 2FA fields
|
||||
totp_secret = db.Column(db.String(32), nullable=True)
|
||||
is_2fa_enabled = db.Column(db.Boolean, default=False)
|
||||
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
|
||||
categories = db.relationship('Category', backref='user', lazy=True, cascade='all, delete-orphan')
|
||||
expenses = db.relationship('Expense', backref='user', lazy=True, cascade='all, delete-orphan')
|
||||
|
||||
def set_password(self, password):
|
||||
self.password_hash = generate_password_hash(password)
|
||||
|
||||
def check_password(self, password):
|
||||
return check_password_hash(self.password_hash, password)
|
||||
|
||||
def generate_totp_secret(self):
|
||||
"""Generate a new TOTP secret"""
|
||||
self.totp_secret = pyotp.random_base32()
|
||||
return self.totp_secret
|
||||
|
||||
def get_totp_uri(self):
|
||||
"""Get TOTP URI for QR code"""
|
||||
if not self.totp_secret:
|
||||
self.generate_totp_secret()
|
||||
return pyotp.totp.TOTP(self.totp_secret).provisioning_uri(
|
||||
name=self.email,
|
||||
issuer_name='FINA'
|
||||
)
|
||||
|
||||
def verify_totp(self, token):
|
||||
"""Verify TOTP token"""
|
||||
if not self.totp_secret:
|
||||
return False
|
||||
totp = pyotp.TOTP(self.totp_secret)
|
||||
return totp.verify(token, valid_window=1)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<User {self.username}>'
|
||||
|
||||
class Tag(db.Model):
|
||||
__tablename__ = 'tags'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(50), nullable=False)
|
||||
color = db.Column(db.String(7), default='#6366f1')
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Tag {self.name}>'
|
||||
Loading…
Add table
Add a link
Reference in a new issue