|
| 1 | +from typing import Tuple |
| 2 | + |
| 3 | +import pandas as pd |
| 4 | +import requests |
| 5 | + |
| 6 | +from config import Config |
| 7 | +from report_api import ReportApi |
| 8 | +from time_entries_api import TimeEntriesApi |
| 9 | + |
| 10 | + |
| 11 | +class ProductivityUpdate: |
| 12 | + def __init__(self): |
| 13 | + self.report = ReportApi() |
| 14 | + |
| 15 | + def _get_daily_message(self) -> str: |
| 16 | + message = "" |
| 17 | + time_api = TimeEntriesApi() |
| 18 | + recent_entries = time_api.get_recent_entries() |
| 19 | + entries = time_api.get_todays_entries(recent_entries) |
| 20 | + if not entries: |
| 21 | + message += self._get_no_work_today_message() |
| 22 | + else: |
| 23 | + summary_df = self.generate_summary_df(entries) |
| 24 | + total_hours, total_minutes = self.get_total_time(summary_df) |
| 25 | + prep_hours, prep_minutes = self.get_special_project_time(summary_df) |
| 26 | + message += self._get_work_done_today_message( |
| 27 | + total_hours, total_minutes, prep_hours, prep_minutes |
| 28 | + ) |
| 29 | + return message |
| 30 | + |
| 31 | + def _get_work_done_today_message( |
| 32 | + self, total_hours: int, total_minutes: int, prep_hours: int, prep_minutes: int |
| 33 | + ) -> str: |
| 34 | + |
| 35 | + return "🕰 Daily stats - Total time: {total_hours} hours and {total_minutes} minutes. Prep time: {prep_hours} hours and {prep_minutes} minutes".format( |
| 36 | + total_hours=total_hours, |
| 37 | + total_minutes=total_minutes, |
| 38 | + prep_hours=prep_hours, |
| 39 | + prep_minutes=prep_minutes, |
| 40 | + ) |
| 41 | + |
| 42 | + def _get_no_work_today_message(self) -> str: |
| 43 | + return "🕰 {} did not work today".format(Config.user_name) |
| 44 | + |
| 45 | + def generate_message(self) -> str: |
| 46 | + message = "Updates for {}\n".format(Config.user_name) |
| 47 | + message += self._get_daily_message() |
| 48 | + weekly_message = ReportApi().report("weekly") |
| 49 | + message += "\n" + weekly_message |
| 50 | + return message |
| 51 | + |
| 52 | + def generate_summary_df(self, entries: list): |
| 53 | + time_api = TimeEntriesApi() |
| 54 | + projects = time_api.get_projects() |
| 55 | + entry_df = time_api.get_entries_df(entries) |
| 56 | + projects_df = time_api.get_projects_df(projects) |
| 57 | + entry_df["hours"] = entry_df["end"] - entry_df["start"] |
| 58 | + entry_df = entry_df.groupby("project_id").agg({"hours": sum}).reset_index() |
| 59 | + summary_df = pd.merge(entry_df, projects_df, on="project_id") |
| 60 | + return summary_df |
| 61 | + |
| 62 | + def get_total_time(self, summary_df: pd.DataFrame) -> Tuple[int, int]: |
| 63 | + total_time = summary_df["hours"].sum().seconds |
| 64 | + total_hours = total_time // (60 * 60) |
| 65 | + total_minutes = (total_time - total_hours * 60 * 60) // 60 |
| 66 | + return total_hours, total_minutes |
| 67 | + |
| 68 | + def get_special_project_time(self, summary_df: pd.DataFrame): |
| 69 | + if Config.special_project_name in summary_df["name"].tolist(): |
| 70 | + prep_time = ( |
| 71 | + summary_df[summary_df["name"] == Config.special_project_name]["hours"] |
| 72 | + .tolist()[0] |
| 73 | + .seconds |
| 74 | + ) |
| 75 | + prep_hours = prep_time // (60 * 60) |
| 76 | + prep_minutes = (prep_time - prep_hours * 60 * 60) // 60 |
| 77 | + return prep_hours, prep_minutes |
| 78 | + else: |
| 79 | + return 0, 0 |
| 80 | + |
| 81 | + def notify(self, message: str) -> int: |
| 82 | + message_dict = {"content": message} |
| 83 | + |
| 84 | + resp = requests.post( |
| 85 | + url=Config.discord_webhook_url, |
| 86 | + json=message_dict, |
| 87 | + headers={"Content-Type": "application/json"}, |
| 88 | + ) |
| 89 | + return 200 |
| 90 | + |
| 91 | + def run(self): |
| 92 | + message = self.generate_message() |
| 93 | + return self.notify(message) |
| 94 | + |
| 95 | + |
| 96 | +if __name__ == "__main__": |
| 97 | + p = ProductivityUpdate() |
| 98 | + p.run() |
0 commit comments