Digitale bierlijst

model.py 8.8KB

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