2021-08-17 02:51:42 +00:00
|
|
|
import json
|
2021-09-12 17:13:43 +00:00
|
|
|
from datetime import datetime, timedelta
|
|
|
|
from fastapi.encoders import jsonable_encoder
|
2021-08-17 02:51:42 +00:00
|
|
|
|
2022-03-13 04:50:33 +00:00
|
|
|
from core.storage import Storage
|
2021-08-17 02:51:42 +00:00
|
|
|
|
2022-03-13 04:50:33 +00:00
|
|
|
storage = Storage("trackers")
|
2021-08-17 02:51:42 +00:00
|
|
|
|
2021-08-23 06:14:40 +00:00
|
|
|
def object_hook(dct):
|
2021-09-12 17:13:43 +00:00
|
|
|
if "datetime" in dct:
|
|
|
|
return TrackerPoint(dct["datetime"], dct["value"])
|
|
|
|
if "date_str" in dct: # old format
|
2021-08-23 06:14:40 +00:00
|
|
|
return TrackerPoint(dct["date_str"], dct["value"])
|
|
|
|
if "name" in dct:
|
|
|
|
return Tracker(dct["name"], dct["points"])
|
|
|
|
|
|
|
|
|
|
|
|
class TrackerPoint:
|
|
|
|
def __init__(self, date_str: str, value: int) -> None:
|
|
|
|
self.datetime = datetime.fromisoformat(date_str)
|
2021-08-17 02:51:42 +00:00
|
|
|
self.value = value
|
|
|
|
|
|
|
|
|
2021-08-23 06:14:40 +00:00
|
|
|
class Tracker:
|
|
|
|
def __init__(self, name: str, points: list[TrackerPoint]):
|
2021-08-17 02:51:42 +00:00
|
|
|
self.name = name
|
|
|
|
self.points = points
|
|
|
|
|
|
|
|
def rename(self, name):
|
2021-08-23 06:14:40 +00:00
|
|
|
"""Rename the Tracker."""
|
2022-03-13 04:50:33 +00:00
|
|
|
storage.rename_file(f"{self.name}.json", f"{name}.json")
|
2021-08-17 02:51:42 +00:00
|
|
|
self.name = name
|
2022-03-13 04:50:33 +00:00
|
|
|
storage.write_file(f"{self.name}.json", jsonable_encoder(self))
|
2021-08-17 02:51:42 +00:00
|
|
|
|
|
|
|
def delete(self):
|
2021-08-23 06:14:40 +00:00
|
|
|
"""Delete the Tracker."""
|
2022-03-13 04:50:33 +00:00
|
|
|
storage.delete_file(f"{self.name}.json")
|
2021-08-17 02:51:42 +00:00
|
|
|
|
2021-08-23 06:14:40 +00:00
|
|
|
def modify_point(self, date_str: str, value: int):
|
2021-08-17 02:51:42 +00:00
|
|
|
"""Modify a point. Change its assigned value to the one given."""
|
2021-08-23 06:14:40 +00:00
|
|
|
date_time = datetime.fromisoformat(date_str)
|
2021-08-17 02:51:42 +00:00
|
|
|
for point in self.points:
|
|
|
|
if point.datetime == date_time:
|
|
|
|
point.value = value
|
|
|
|
break
|
2022-03-13 04:50:33 +00:00
|
|
|
storage.write_file(f"{self.name}.json", jsonable_encoder(self))
|
2021-08-17 02:51:42 +00:00
|
|
|
|
2021-08-23 06:14:40 +00:00
|
|
|
def add_point(self, date_str: str, value: int):
|
2021-08-17 02:51:42 +00:00
|
|
|
"""Add a point to the tracker."""
|
2021-08-23 06:14:40 +00:00
|
|
|
point = TrackerPoint(date_str, value)
|
2021-08-17 02:51:42 +00:00
|
|
|
self.points.append(point)
|
2022-03-13 04:50:33 +00:00
|
|
|
storage.write_file(f"{self.name}.json", jsonable_encoder(self))
|
2021-08-17 02:51:42 +00:00
|
|
|
|
2021-08-23 06:14:40 +00:00
|
|
|
def delete_point(self, date_str: str):
|
2021-08-17 02:51:42 +00:00
|
|
|
"""Remove a point from the tracker."""
|
2021-08-23 06:14:40 +00:00
|
|
|
date_time = datetime.fromisoformat(date_str)
|
2021-08-17 02:51:42 +00:00
|
|
|
for point in self.points:
|
|
|
|
if point.datetime == date_time:
|
|
|
|
self.points.remove(point)
|
|
|
|
break
|
2022-03-13 04:50:33 +00:00
|
|
|
storage.write_file(f"{self.name}.json", jsonable_encoder(self))
|
2021-08-17 02:51:42 +00:00
|
|
|
|
2021-09-12 17:13:43 +00:00
|
|
|
def list_points(self, start_date: datetime = None, end_date: datetime = None) -> list:
|
|
|
|
"""
|
|
|
|
Return a list of all points that fall in-between the given start_date and end_date.
|
|
|
|
|
|
|
|
:param start_date: the date the data returned should start at.
|
|
|
|
If this is not given, it'll be a week from the given end_date.
|
|
|
|
|
|
|
|
:param end_date: the date the data returned should end at. (included in output)
|
|
|
|
If this is not given, it'll be today.
|
|
|
|
|
|
|
|
:return: list of all points that fall in-between the given start_date and end_date.
|
|
|
|
|
|
|
|
:raises ValueError: if either date parameter is set in the future, or if the end_date is before the start_date.
|
|
|
|
"""
|
|
|
|
point_list = []
|
|
|
|
if end_date is None:
|
|
|
|
end_date = datetime.now().date()
|
|
|
|
if start_date is None:
|
|
|
|
start_date = (end_date - timedelta(days=7)) # assume we'll start a week prior to today.
|
|
|
|
if end_date > datetime.now().date() or start_date > datetime.now().date() or end_date < start_date:
|
|
|
|
raise ValueError(end_date)
|
|
|
|
for point in self.points:
|
|
|
|
if start_date <= point.datetime.date() <= end_date:
|
|
|
|
point_list.append(point)
|
|
|
|
return point_list
|
|
|
|
|
2021-08-17 02:51:42 +00:00
|
|
|
@classmethod
|
|
|
|
def from_data(cls, name):
|
2021-08-23 06:14:40 +00:00
|
|
|
"""Load a tracker from the DATA_DIR."""
|
2022-03-13 04:50:33 +00:00
|
|
|
data = storage.read_file(f"{name}.json")
|
|
|
|
return cls.from_json(data)
|
2021-08-17 02:51:42 +00:00
|
|
|
|
2021-08-23 06:14:40 +00:00
|
|
|
@staticmethod
|
|
|
|
def from_json(json_str):
|
|
|
|
"""Load a tracker from a JSON string."""
|
2022-03-13 04:50:33 +00:00
|
|
|
return json.load(json_str, object_hook=object_hook)
|