At its starting state it would accept following commands: - !getunits <activity>: Would send a JSON file with activity units via Discord message. Those files are responsible for setting up a fitness activity to log. - !getlog <activity>: Would send a CSV file with fitness activity log. Those files contain records with timestamp, username, and reported activity measurements. - !<activity> <value> <unit (optional)>: Would create a record with your fitness activity in corresponding CSV log file. If you choose to report different unit (feet, for example), it is going to convert as specified in its corresponding JSON file with units (to meters, for example) if the activity specified as convertable. Non-convertable activities' units are ignored.
120 lines
3.1 KiB
Python
120 lines
3.1 KiB
Python
import json
|
|
import csv
|
|
import os
|
|
|
|
|
|
def activity_log_path(activity: str) -> str:
|
|
"""
|
|
Returns the path of the activity log file in .csv format
|
|
:param activity:
|
|
:return:
|
|
"""
|
|
filename = os.path.join("activity_logs", f"{activity}.csv")
|
|
return filename
|
|
|
|
|
|
def activity_units_path(activity: str) -> str:
|
|
"""
|
|
Returns the path of the activity activities file in .json format
|
|
:param activity:
|
|
:return:
|
|
"""
|
|
filename = os.path.join("activities", f"{activity}.json")
|
|
return filename
|
|
|
|
|
|
def is_convertable(activity: str) -> bool:
|
|
"""
|
|
Returns True if the activity has multiple units that needed to be converted.
|
|
i.e. distance may be sent in feet, but would require to be converted in meters.
|
|
:param activity:
|
|
:return:
|
|
"""
|
|
filename = activity_units_path(activity)
|
|
raw_data = json.load(open(filename))
|
|
return raw_data.get("transformable")
|
|
|
|
|
|
|
|
def create_activity_log_file(activity: str) -> None:
|
|
"""
|
|
Creates the activity log file in .csv format
|
|
:param activity:
|
|
:return:
|
|
"""
|
|
if not os.path.exists(activity_units_path(activity)):
|
|
raise ValueError(f"{activity} is not a valid activity")
|
|
if not os.path.exists("activity_logs"):
|
|
os.makedirs("activity_logs")
|
|
filename = activity_log_path(activity)
|
|
with open(filename, 'a') as f:
|
|
writer = csv.writer(f)
|
|
writer.writerow(["timestamp", "username", "value"])
|
|
|
|
|
|
|
|
def convert_units(activity: str, value: int | float, unit: str) -> float:
|
|
"""
|
|
Returns the value of activity in a factor of 1, i.e. converting feet to meters
|
|
:param activity:
|
|
:param value:
|
|
:param unit:
|
|
:return:
|
|
"""
|
|
filename = activity_units_path(activity)
|
|
if not os.path.exists(filename):
|
|
raise ValueError(f"{activity} is not a valid activity")
|
|
|
|
# Consider None unit value as factor of 1
|
|
if unit is None:
|
|
return value
|
|
|
|
raw_data = json.load(open(filename))
|
|
units_data = raw_data.get("units")
|
|
|
|
for unit_name, data in units_data.items():
|
|
if unit in data["aliases"]:
|
|
return value * data["factor"]
|
|
|
|
raise ValueError(f"{unit} is not a valid unit")
|
|
|
|
|
|
def log_activity(
|
|
timestamp: int,
|
|
username: str,
|
|
activity: str,
|
|
value: int | float,
|
|
unit: str | None
|
|
) -> None:
|
|
"""
|
|
Logs the activity in .csv file
|
|
:param timestamp:
|
|
:param username:
|
|
:param activity:
|
|
:param value:
|
|
:param unit:
|
|
:return:
|
|
"""
|
|
if value <= 0 or not isinstance(value, int | float):
|
|
raise ValueError(f"{value} is not a valid value")
|
|
filename = activity_log_path(activity)
|
|
if not os.path.exists(filename):
|
|
create_activity_log_file(activity)
|
|
if is_convertable(activity):
|
|
converted_value = round(convert_units(activity, value, unit), 2)
|
|
else:
|
|
converted_value = round(value, 2)
|
|
with open(filename, 'a') as f:
|
|
writer = csv.writer(f)
|
|
writer.writerow([timestamp, username, converted_value])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
log_activity(
|
|
timestamp=0,
|
|
username="test",
|
|
activity="climb",
|
|
value=1,
|
|
unit="m"
|
|
)
|