Digitale bierlijst

model.py 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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, active=None) -> ["Person"]:
  80. """ Get all active People. """
  81. active = int(active)
  82. req = requests.get(urljoin(SERVER_URL, "/people"),
  83. params={'active':active})
  84. try:
  85. data = req.json()
  86. if "error" in data:
  87. LOG.warning("Could not get people (%s): %s", req.status_code, data)
  88. return [Person.from_dict(item) for item in data["people"]]
  89. except ValueError:
  90. LOG.error(
  91. "Did not get JSON from server on getting People (%s): %s",
  92. req.status_code,
  93. req.content,
  94. )
  95. return None
  96. @classmethod
  97. def from_dict(cls, data: dict) -> "Person":
  98. """ Reconstruct a Person object from a dict. """
  99. return Person(
  100. name=data["name"],
  101. person_id=data["person_id"],
  102. consumptions=data["consumptions"],
  103. )
  104. class ConsumptionType(NamedTuple):
  105. """ Represents a stored ConsumptionType. """
  106. name: str
  107. consumption_type_id: int = None
  108. icon: str = None
  109. def create(self) -> "ConsumptionType":
  110. """ Create a new ConsumptionType from the current attributes. As tuples
  111. are immutable, a new ConsumptionType with the correct id is returned.
  112. """
  113. req = requests.post(
  114. urljoin(SERVER_URL, "consumption_types"),
  115. json={"consumption_type": {"name": self.name, "icon": self.icon}},
  116. )
  117. try:
  118. data = req.json()
  119. except ValueError:
  120. LOG.error(
  121. "Did not get JSON on adding ConsumptionType (%s): %s",
  122. req.status_code,
  123. req.content,
  124. )
  125. return None
  126. if "error" in data or req.status_code != 201:
  127. LOG.error(
  128. "Could not create ConsumptionType (%s): %s", req.status_code, data
  129. )
  130. return None
  131. return ConsumptionType.from_dict(data["consumption_type"])
  132. @classmethod
  133. def get(cls, consumption_type_id: int) -> "ConsumptionType":
  134. """ Retrieve a ConsumptionType by id. """
  135. req = requests.get(
  136. urljoin(SERVER_URL, f"/consumption_types/{consumption_type_id}")
  137. )
  138. try:
  139. data = req.json()
  140. if "error" in data:
  141. LOG.warning(
  142. "Could not get consumption type %s (%s): %s",
  143. consumption_type_id,
  144. req.status_code,
  145. data,
  146. )
  147. return None
  148. return cls.from_dict(data["consumption_type"])
  149. except ValueError:
  150. LOG.error(
  151. "Did not get JSON from server on getting consumption type (%s): %s",
  152. req.status_code,
  153. req.content,
  154. )
  155. return None
  156. @classmethod
  157. def get_all(cls) -> ["ConsumptionType"]:
  158. """ Get all active ConsumptionTypes. """
  159. req = requests.get(urljoin(SERVER_URL, "/consumption_types"))
  160. try:
  161. data = req.json()
  162. if "error" in data:
  163. LOG.warning(
  164. "Could not get consumption types (%s): %s", req.status_code, data
  165. )
  166. return [cls.from_dict(item) for item in data["consumption_types"]]
  167. except ValueError:
  168. LOG.error(
  169. "Did not get JSON from server on getting ConsumptionTypes (%s): %s",
  170. req.status_code,
  171. req.content,
  172. )
  173. return None
  174. @classmethod
  175. def from_dict(cls, data: dict) -> "ConsumptionType":
  176. """ Reconstruct a ConsumptionType from a dict. """
  177. return cls(
  178. name=data["name"],
  179. consumption_type_id=data["consumption_type_id"],
  180. icon=data.get("icon"),
  181. )
  182. class Consumption(NamedTuple):
  183. """ Represents a stored Consumption. """
  184. consumption_id: int
  185. person_id: int
  186. consumption_type_id: int
  187. created_at: datetime.datetime
  188. reversed: bool = False
  189. settlement_id: int = None
  190. @classmethod
  191. def from_dict(cls, data: dict) -> "Consumption":
  192. """ Reconstruct a Consumption from a dict. """
  193. return cls(
  194. consumption_id=data["consumption_id"],
  195. person_id=data["person_id"],
  196. consumption_type_id=data["consumption_type_id"],
  197. settlement_id=data["settlement_id"],
  198. created_at=datetime.datetime.fromisoformat(data["created_at"]),
  199. reversed=data["reversed"],
  200. )
  201. def reverse(self) -> "Consumption":
  202. """ Reverse this consumption. """
  203. req = requests.delete(
  204. urljoin(SERVER_URL, f"/consumptions/{self.consumption_id}")
  205. )
  206. try:
  207. data = req.json()
  208. if "error" in data:
  209. LOG.error(
  210. "Could not reverse consumption %s (%s): %s",
  211. self.consumption_id,
  212. req.status_code,
  213. data,
  214. )
  215. return False
  216. return Consumption.from_dict(data["consumption"])
  217. except ValueError:
  218. LOG.error(
  219. "Did not get JSON on reversing Consumption (%s): %s",
  220. req.status_code,
  221. req.content,
  222. )
  223. return False