user.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  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. class User(db.Model):
  8. """User model for authentication and authorization"""
  9. __tablename__ = 'users'
  10. id = db.Column(db.Integer, primary_key=True)
  11. username = db.Column(db.String(50), unique=True, nullable=False, index=True)
  12. email = db.Column(db.String(100), unique=True, nullable=False, index=True)
  13. password_hash = db.Column(db.String(255), nullable=False)
  14. role = db.Column(db.Enum('admin', 'power_user', 'user', name='user_role'), default='user')
  15. created_at = db.Column(db.DateTime, default=utc_now)
  16. is_active = db.Column(db.Boolean, default=True)
  17. # Relationships
  18. credentials = db.relationship('UserCredential', back_populates='user', cascade='all, delete-orphan')
  19. tasks = db.relationship('Task', back_populates='created_by_user', cascade='all, delete-orphan')
  20. def set_password(self, password: str) -> None:
  21. """Hash and set the user's password"""
  22. self.password_hash = bcrypt.hashpw(
  23. password.encode('utf-8'),
  24. bcrypt.gensalt()
  25. ).decode('utf-8')
  26. def check_password(self, password: str) -> bool:
  27. """Verify the user's password"""
  28. return bcrypt.checkpw(
  29. password.encode('utf-8'),
  30. self.password_hash.encode('utf-8')
  31. )
  32. def to_dict(self) -> dict:
  33. """Convert user to dictionary (excluding sensitive data)"""
  34. return {
  35. 'id': self.id,
  36. 'username': self.username,
  37. 'email': self.email,
  38. 'role': self.role,
  39. 'created_at': self.created_at.isoformat() if self.created_at else None,
  40. 'is_active': self.is_active
  41. }
  42. def __repr__(self):
  43. return f'<User {self.username}>'