Digitale bierlijst

model.py 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. """
  2. Provides access to the models stored in the database, via the server.
  3. """
  4. import datetime
  5. from typing import NamedTuple
  6. from urllib.parse import urljoin
  7. import requests
  8. from . import logger
  9. LOG = logger.getLogger("model")
  10. SERVER_URL = "http://127.0.0.1:5000"
  11. class Person(NamedTuple):
  12. """ Represents a Person, as retrieved from the database. """
  13. name: str
  14. person_id: int = None
  15. consumptions: dict = {}
  16. def add_consumption(self, type_id: str) -> bool:
  17. """ Register a consumption for this Person. """
  18. req = requests.post(
  19. urljoin(SERVER_URL, f"people/{self.person_id}/add_consumption/{type_id}")
  20. )
  21. try:
  22. data = req.json()
  23. if "error" in data:
  24. LOG.error(
  25. "Could not add consumption for %s (%s): %s",
  26. self.person_id,
  27. req.status_code,
  28. data,
  29. )
  30. return False
  31. self.consumptions.update(data["person"]["consumptions"])
  32. return Consumption.from_dict(data["consumption"])
  33. except ValueError:
  34. LOG.error(
  35. "Did not get JSON on adding Consumption (%s): %s",
  36. req.status_code,
  37. req.content,
  38. )
  39. return False
  40. def create(self) -> "Person":
  41. """ Create a new Person from the current attributes. As tuples are
  42. immutable, a new Person with the correct id is returned. """
  43. req = requests.post(
  44. urljoin(SERVER_URL, "people"), json={"person": {"name": self.name}}
  45. )
  46. try:
  47. data = req.json()
  48. except ValueError:
  49. LOG.error(
  50. "Did not get JSON on adding Person (%s): %s",
  51. req.status_code,
  52. req.content,
  53. )
  54. return None
  55. if "error" in data or req.status_code != 201:
  56. LOG.error("Could not create Person (%s): %s", req.status_code, data)
  57. return None
  58. return Person.from_dict(data["person"])
  59. @classmethod
  60. def get(cls, person_id: int) -> "Person":
  61. """ Retrieve a Person by id. """
  62. req = requests.get(urljoin(SERVER_URL, f"/people/{person_id}"))
  63. try:
  64. data = req.json()
  65. if "error" in data:
  66. LOG.warning(
  67. "Could not get person %s (%s): %s", person_id, req.status_code, data
  68. )
  69. return None
  70. return Person.from_dict(data["person"])
  71. except ValueError:
  72. LOG.error(
  73. "Did not get JSON from server on getting Person (%s): %s",
  74. req.status_code,
  75. req.content,
  76. )
  77. return None
  78. @classmethod
  79. def get_all(cls) -> ["Person"]:
  80. """ Get all active People. """
  81. req = requests.get(urljoin(SERVER_URL, "/people"))
  82. try:
  83. data = req.json()
  84. if "error" in data:
  85. LOG.warning("Could not get people (%s): %s", req.status_code, data)
  86. return [Person.from_dict(item) for item in data["people"]]
  87. except ValueError:
  88. LOG.error(
  89. "Did not get JSON from server on getting People (%s): %s",
  90. req.status_code,
  91. req.content,
  92. )
  93. return None
  94. @classmethod
  95. def from_dict(cls, data: dict) -> "Person":
  96. """ Reconstruct a Person object from a dict. """
  97. return Person(
  98. name=data["name"],
  99. person_id=data["person_id"],
  100. consumptions=data["consumptions"],
  101. )
  102. class ConsumptionType(NamedTuple):
  103. """ Represents a stored ConsumptionType. """
  104. name: str
  105. consumption_type_id: int = None
  106. icon: str = None
  107. def create(self) -> "ConsumptionType":
  108. """ Create a new ConsumptionType from the current attributes. As tuples
  109. are immutable, a new ConsumptionType with the correct id is returned.
  110. """
  111. req = requests.post(
  112. urljoin(SERVER_URL, "consumption_types"),
  113. json={"consumption_type": {"name": self.name, "icon": self.icon}},
  114. )
  115. try:
  116. data = req.json()
  117. except ValueError:
  118. LOG.error(
  119. "Did not get JSON on adding ConsumptionType (%s): %s",
  120. req.status_code,
  121. req.content,
  122. )
  123. return None
  124. if "error" in data or req.status_code != 201:
  125. LOG.error(
  126. "Could not create ConsumptionType (%s): %s", req.status_code, data
  127. )
  128. return None
  129. return ConsumptionType.from_dict(data["consumption_type"])
  130. @classmethod
  131. def get(cls, consumption_type_id: int) -> "ConsumptionType":
  132. """ Retrieve a ConsumptionType by id. """
  133. req = requests.get(
  134. urljoin(SERVER_URL, f"/consumption_types/{consumption_type_id}")
  135. )
  136. try:
  137. data = req.json()
  138. if "error" in data:
  139. LOG.warning(
  140. "Could not get consumption type %s (%s): %s",
  141. consumption_type_id,
  142. req.status_code,
  143. data,
  144. )
  145. return None
  146. return cls.from_dict(data["consumption_type"])
  147. except ValueError:
  148. LOG.error(
  149. "Did not get JSON from server on getting consumption type (%s): %s",
  150. req.status_code,
  151. req.content,
  152. )
  153. return None
  154. @classmethod
  155. def get_all(cls) -> ["ConsumptionType"]:
  156. """ Get all active ConsumptionTypes. """
  157. req = requests.get(urljoin(SERVER_URL, "/consumption_types"))
  158. try:
  159. data = req.json()
  160. if "error" in data:
  161. LOG.warning(
  162. "Could not get consumption types (%s): %s", req.status_code, data
  163. )
  164. return [cls.from_dict(item) for item in data["consumption_types"]]
  165. except ValueError:
  166. LOG.error(
  167. "Did not get JSON from server on getting ConsumptionTypes (%s): %s",
  168. req.status_code,
  169. req.content,
  170. )
  171. return None
  172. @classmethod
  173. def from_dict(cls, data: dict) -> "ConsumptionType":
  174. """ Reconstruct a ConsumptionType from a dict. """
  175. return cls(
  176. name=data["name"],
  177. consumption_type_id=data["consumption_type_id"],
  178. icon=data.get("icon"),
  179. )
  180. class Consumption(NamedTuple):
  181. """ Represents a stored Consumption. """
  182. consumption_id: int
  183. person_id: int
  184. consumption_type_id: int
  185. created_at: datetime.datetime
  186. reversed: bool = False
  187. settlement_id: int = None
  188. @classmethod
  189. def from_dict(cls, data: dict) -> "Consumption":
  190. """ Reconstruct a Consumption from a dict. """
  191. return cls(
  192. consumption_id=data["consumption_id"],
  193. person_id=data["person_id"],
  194. consumption_type_id=data["consumption_type_id"],
  195. settlement_id=data["settlement_id"],
  196. created_at=datetime.datetime.fromisoformat(data["created_at"]),
  197. reversed=data["reversed"],
  198. )
  199. def reverse(self) -> "Consumption":
  200. """ Reverse this consumption. """
  201. req = requests.delete(
  202. urljoin(SERVER_URL, f"/consumptions/{self.consumption_id}")
  203. )
  204. try:
  205. data = req.json()
  206. if "error" in data:
  207. LOG.error(
  208. "Could not reverse consumption %s (%s): %s",
  209. self.consumption_id,
  210. req.status_code,
  211. data,
  212. )
  213. return False
  214. return Consumption.from_dict(data["consumption"])
  215. except ValueError:
  216. LOG.error(
  217. "Did not get JSON on reversing Consumption (%s): %s",
  218. req.status_code,
  219. req.content,
  220. )
  221. return False