41 lines
1.3 KiB
Python
41 lines
1.3 KiB
Python
import re
|
|
|
|
from sqlalchemy import Boolean, Column, String
|
|
from sqlalchemy.orm import validates
|
|
|
|
from app.db.base_class import Base
|
|
|
|
|
|
class User(Base):
|
|
"""
|
|
User model with flexible authentication (username or email).
|
|
"""
|
|
username = Column(String, unique=True, index=True, nullable=True)
|
|
email = Column(String, unique=True, index=True, nullable=True)
|
|
hashed_password = Column(String, nullable=False)
|
|
is_active = Column(Boolean, default=True)
|
|
is_superuser = Column(Boolean, default=False)
|
|
|
|
@validates('email')
|
|
def validate_email(self, key, email):
|
|
if email is None:
|
|
return email
|
|
|
|
# Simple email validation regex
|
|
if not re.match(r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', email):
|
|
raise ValueError('Invalid email format')
|
|
return email
|
|
|
|
@validates('username')
|
|
def validate_username(self, key, username):
|
|
if username is None:
|
|
return username
|
|
|
|
# Username validation: alphanumeric + underscore, 3-20 chars
|
|
if not re.match(r'^[a-zA-Z0-9_]{3,20}$', username):
|
|
raise ValueError(
|
|
'Username must be 3-20 characters and contain only letters, numbers, '
|
|
'and underscores'
|
|
)
|
|
return username
|