schema.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. from typing import Any
  2. from ninja import ModelSchema
  3. from ninja.errors import ValidationError
  4. from pydantic import ValidationInfo, field_validator
  5. from bitfield.types import BitHandler
  6. from .models import APIToken
  7. def bitfield_to_internal_value(model, v: Any, info: ValidationInfo) -> int:
  8. if not info.field_name:
  9. raise Exception("Improperly used bitfield_to_internal_value")
  10. if isinstance(v, list):
  11. model_field = getattr(model, info.field_name)
  12. result = BitHandler(0, model_field.keys())
  13. for k in v:
  14. try:
  15. setattr(result, str(k), True)
  16. except AttributeError:
  17. raise ValidationError([{"scopes": "Invalid scope"}])
  18. v = result
  19. if isinstance(v, BitHandler):
  20. return v.mask
  21. return v
  22. class APITokenIn(ModelSchema):
  23. scopes: int
  24. class Meta:
  25. model = APIToken
  26. fields = ("label",)
  27. fields_optional = ["label"]
  28. @field_validator("scopes", mode="before")
  29. @classmethod
  30. def scopes_to_bitfield(cls, v, info: ValidationInfo):
  31. return bitfield_to_internal_value(cls.Meta.model, v, info)
  32. class APITokenSchema(ModelSchema):
  33. scopes: list[str]
  34. class Meta:
  35. model = APIToken
  36. fields = ("label", "created", "token", "id")
  37. @staticmethod
  38. def resolve_scopes(obj) -> list[str]:
  39. """Example: ['member:read']"""
  40. scopes: BitHandler
  41. # Must accept both kwarg and model object
  42. if isinstance(obj, APIToken):
  43. scopes = obj.scopes
  44. if isinstance(obj, dict):
  45. scopes = obj.get("scopes")
  46. return [i[0] for i in scopes.items() if i[1] is True]