request.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import abc
  2. from dataclasses import dataclass
  3. from dataclasses_json import dataclass_json
  4. from datetime import datetime
  5. from typing import List, Mapping, Optional, TypeVar, Type
  6. import lc.config as c
  7. import lc.error as e
  8. T = TypeVar("T")
  9. class Request(metaclass=abc.ABCMeta):
  10. @classmethod
  11. @abc.abstractmethod
  12. def from_form(cls: Type[T], form: Mapping[str, str]) -> T:
  13. pass
  14. # technically this gets added by dataclass_json, but mypy isn't
  15. # aware of it, so it's going to get declared here as though it
  16. # weren't abstract and then dataclass_json will add it
  17. @classmethod
  18. def from_json(cls: Type[T], json: bytes) -> T:
  19. pass
  20. @dataclass_json
  21. @dataclass
  22. class User(Request):
  23. name: str
  24. password: str
  25. @classmethod
  26. def from_form(cls, form: Mapping[str, str]):
  27. return cls(name=form["username"], password=form["password"],)
  28. def to_token(self) -> str:
  29. return c.serializer.dumps({"name": self.name})
  30. @dataclass_json
  31. @dataclass
  32. class NewUser(Request):
  33. name: str
  34. n1: str
  35. n2: str
  36. @classmethod
  37. def from_form(cls, form: Mapping[str, str]):
  38. return cls(name=form["username"], n1=form["n1"], n2=form["n2"],)
  39. def to_user_request(self) -> User:
  40. if self.n1 != self.n2:
  41. raise e.MismatchedPassword()
  42. return User(name=self.name, password=self.n1)
  43. @dataclass_json
  44. @dataclass
  45. class PasswordChange(Request):
  46. n1: str
  47. n2: str
  48. old: str
  49. @classmethod
  50. def from_form(cls, form: Mapping[str, str]):
  51. return cls(old=form["old"], n1=form["n1"], n2=form["n2"],)
  52. def require_match(self):
  53. if self.n1 != self.n2:
  54. raise e.MismatchedPassword()
  55. @dataclass_json
  56. @dataclass
  57. class Link(Request):
  58. url: str
  59. name: str
  60. description: str
  61. private: bool
  62. tags: List[str]
  63. created: Optional[datetime] = None
  64. @classmethod
  65. def from_form(cls, form: Mapping[str, str]):
  66. return cls(
  67. url=form["url"],
  68. name=form["name"],
  69. description=form["description"],
  70. private="private" in form,
  71. tags=form["tags"].split(),
  72. )