user.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. from datetime import datetime, timezone
  2. from app import db
  3. import bcrypt
  4. def utc_now():
  5. """Return current UTC time as timezone-aware datetime"""
  6. return datetime.now(timezone.utc)
  7. def format_datetime(dt: datetime) -> str:
  8. """Format datetime to ISO format with UTC timezone indicator"""
  9. if dt is None:
  10. return None
  11. # If datetime is naive (no timezone), assume it's UTC
  12. if dt.tzinfo is None:
  13. dt = dt.replace(tzinfo=timezone.utc)
  14. return dt.isoformat()
  15. class User(db.Model):
  16. """User model for authentication and authorization"""
  17. __tablename__ = 'users'
  18. id = db.Column(db.Integer, primary_key=True)
  19. username = db.Column(db.String(50), unique=True, nullable=False, index=True)
  20. email = db.Column(db.String(100), unique=True, nullable=False, index=True)
  21. password_hash = db.Column(db.String(255), nullable=False)
  22. role = db.Column(db.Enum('admin', 'power_user', 'user', name='user_role'), default='user')
  23. created_at = db.Column(db.DateTime, default=utc_now)
  24. is_active = db.Column(db.Boolean, default=True)
  25. # Relationships
  26. credentials = db.relationship('UserCredential', back_populates='user', cascade='all, delete-orphan')
  27. tasks = db.relationship('Task', back_populates='created_by_user', cascade='all, delete-orphan')
  28. def set_password(self, password: str) -> None:
  29. """Hash and set the user's password"""
  30. self.password_hash = bcrypt.hashpw(
  31. password.encode('utf-8'),
  32. bcrypt.gensalt()
  33. ).decode('utf-8')
  34. def check_password(self, password: str) -> bool:
  35. """Verify the user's password"""
  36. return bcrypt.checkpw(
  37. password.encode('utf-8'),
  38. self.password_hash.encode('utf-8')
  39. )
  40. def to_dict(self) -> dict:
  41. """Convert user to dictionary (excluding sensitive data)"""
  42. return {
  43. 'id': self.id,
  44. 'username': self.username,
  45. 'email': self.email,
  46. 'role': self.role,
  47. 'created_at': format_datetime(self.created_at),
  48. 'is_active': self.is_active
  49. }
  50. def __repr__(self):
  51. return f'<User {self.username}>'