account.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. from flask.cli import with_appcontext
  2. from flexmeasures.data import ma
  3. from marshmallow import fields, validates
  4. from flexmeasures.data import db
  5. from flexmeasures.data.models.user import (
  6. Account as AccountModel,
  7. AccountRole as AccountRoleModel,
  8. )
  9. from flexmeasures.data.schemas.utils import FMValidationError, MarshmallowClickMixin
  10. from flexmeasures.utils.validation_utils import validate_color_hex, validate_url
  11. class AccountRoleSchema(ma.SQLAlchemySchema):
  12. """AccountRole schema, with validations."""
  13. class Meta:
  14. model = AccountRoleModel
  15. id = ma.auto_field(dump_only=True)
  16. name = ma.auto_field()
  17. accounts = fields.Nested("AccountSchema", exclude=("account_roles",), many=True)
  18. class AccountSchema(ma.SQLAlchemySchema):
  19. """Account schema, with validations."""
  20. class Meta:
  21. model = AccountModel
  22. id = ma.auto_field(dump_only=True)
  23. name = ma.auto_field(required=True)
  24. primary_color = ma.auto_field(required=False)
  25. secondary_color = ma.auto_field(required=False)
  26. logo_url = ma.auto_field(required=False)
  27. account_roles = fields.Nested("AccountRoleSchema", exclude=("accounts",), many=True)
  28. consultancy_account_id = ma.auto_field()
  29. @validates("primary_color")
  30. def validate_primary_color(self, value):
  31. try:
  32. validate_color_hex(value)
  33. except ValueError as e:
  34. raise FMValidationError(str(e))
  35. @validates("secondary_color")
  36. def validate_secondary_color(self, value):
  37. try:
  38. validate_color_hex(value)
  39. except ValueError as e:
  40. raise FMValidationError(str(e))
  41. @validates("logo_url")
  42. def validate_logo_url(self, value):
  43. try:
  44. validate_url(value)
  45. except ValueError as e:
  46. raise FMValidationError(str(e))
  47. class AccountIdField(fields.Int, MarshmallowClickMixin):
  48. """Field that deserializes to an Account and serializes back to an integer."""
  49. @with_appcontext
  50. def _deserialize(self, value, attr, obj, **kwargs) -> AccountModel:
  51. """Turn an account id into an Account."""
  52. account = db.session.get(AccountModel, value)
  53. if account is None:
  54. raise FMValidationError(f"No account found with id {value}.")
  55. # lazy loading now (account somehow is not in the session after this)
  56. account.account_roles
  57. return account
  58. def _serialize(self, account, attr, data, **kwargs):
  59. """Turn an Account into a source id."""
  60. return account.id