organization.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. """
  2. Organization model - represents a client company.
  3. """
  4. from sqlalchemy import Boolean, String
  5. from sqlalchemy.orm import Mapped, mapped_column, relationship
  6. from app.core.encryption import decrypt_password, encrypt_password
  7. from app.models.base import Base
  8. class Organization(Base):
  9. """
  10. Organization (client company) model.
  11. Each organization can have multiple users and devices.
  12. Products (WiFi, BLE) are enabled/disabled per organization.
  13. """
  14. __tablename__ = "organizations"
  15. id: Mapped[int] = mapped_column(primary_key=True)
  16. name: Mapped[str] = mapped_column(String(255), nullable=False)
  17. contact_email: Mapped[str] = mapped_column(String(255), nullable=False)
  18. contact_phone: Mapped[str | None] = mapped_column(String(50))
  19. # Product access (modular)
  20. wifi_enabled: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
  21. ble_enabled: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
  22. # WiFi credentials (encrypted)
  23. wifi_ssid: Mapped[str | None] = mapped_column(String(100))
  24. _wifi_password_encrypted: Mapped[str | None] = mapped_column(
  25. "wifi_password_encrypted", String(500)
  26. )
  27. # Status: pending, active, suspended, deleted
  28. status: Mapped[str] = mapped_column(
  29. String(20), default="pending", nullable=False
  30. )
  31. # Admin notes
  32. notes: Mapped[str | None] = mapped_column(String)
  33. # Relationships
  34. users: Mapped[list["User"]] = relationship(
  35. "User", back_populates="organization", cascade="all, delete-orphan"
  36. )
  37. devices: Mapped[list["Device"]] = relationship(
  38. "Device", back_populates="organization"
  39. )
  40. @property
  41. def wifi_password(self) -> str | None:
  42. """Decrypt WiFi password for viewing by admin."""
  43. if not self._wifi_password_encrypted:
  44. return None
  45. return decrypt_password(self._wifi_password_encrypted)
  46. @wifi_password.setter
  47. def wifi_password(self, plain_password: str | None) -> None:
  48. """Encrypt WiFi password before storing."""
  49. if plain_password is None:
  50. self._wifi_password_encrypted = None
  51. else:
  52. self._wifi_password_encrypted = encrypt_password(plain_password)
  53. def __repr__(self) -> str:
  54. return f"<Organization {self.id}: {self.name}>"