remove duplications
This commit is contained in:
@@ -97,4 +97,10 @@ The application requires:
|
|||||||
- The system enforces task constraints within work desktops - switching to a non-work task automatically reverts to the designated work task
|
- The system enforces task constraints within work desktops - switching to a non-work task automatically reverts to the designated work task
|
||||||
- Task files are monitored for changes to enable automatic context switching
|
- Task files are monitored for changes to enable automatic context switching
|
||||||
- Web interface runs on port 10000 by default
|
- Web interface runs on port 10000 by default
|
||||||
- Core daemon sleeps for 2 seconds between workspace checks
|
- Core daemon sleeps for 2 seconds between workspace checks
|
||||||
|
|
||||||
|
## Tool Development Guidelines
|
||||||
|
|
||||||
|
- This is a personal tool, not professionally developed
|
||||||
|
- reuse as it is as much as possible unless refactor is required explicitly, suggest improvements
|
||||||
|
- Only modify existing code if it absolutely doesn't make sense to add a new flow
|
||||||
@@ -2,7 +2,7 @@ from datetime import datetime, timedelta
|
|||||||
|
|
||||||
from flask import Blueprint, render_template
|
from flask import Blueprint, render_template
|
||||||
|
|
||||||
from .get_period_times import get_period_totals, task_or_none, timezone
|
from .get_period_times import get_period_totals, task_or_none, timezone, get_work_project_tasks, get_work_period_totals
|
||||||
|
|
||||||
dmbp = Blueprint("deskmeter", __name__, url_prefix="/", template_folder="templates")
|
dmbp = Blueprint("deskmeter", __name__, url_prefix="/", template_folder="templates")
|
||||||
|
|
||||||
@@ -66,6 +66,20 @@ def period(start, end):
|
|||||||
return render_template("pages.html", rows=rows)
|
return render_template("pages.html", rows=rows)
|
||||||
|
|
||||||
|
|
||||||
|
@dmbp.route("/work")
|
||||||
|
def work():
|
||||||
|
"""
|
||||||
|
Show total time used per work project for today
|
||||||
|
"""
|
||||||
|
start = datetime.today().replace(hour=0, minute=0, second=0, tzinfo=timezone)
|
||||||
|
end = datetime.today().replace(hour=23, minute=59, second=59, tzinfo=timezone)
|
||||||
|
|
||||||
|
rows = get_work_period_totals(start, end)
|
||||||
|
print(rows)
|
||||||
|
|
||||||
|
return render_template("main.html", rows=rows)
|
||||||
|
|
||||||
|
|
||||||
@dmbp.route("/totals")
|
@dmbp.route("/totals")
|
||||||
@dmbp.route("/totals/<string:task>")
|
@dmbp.route("/totals/<string:task>")
|
||||||
def totals(task=None):
|
def totals(task=None):
|
||||||
|
|||||||
@@ -12,13 +12,17 @@ from .get_period_times import (
|
|||||||
task_file,
|
task_file,
|
||||||
task_or_none,
|
task_or_none,
|
||||||
timezone,
|
timezone,
|
||||||
|
get_work_project_tasks,
|
||||||
|
get_work_period_totals,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DMHTMLCalendar(calendar.HTMLCalendar):
|
class DMHTMLCalendar(calendar.HTMLCalendar):
|
||||||
# def formatmonth(self, theyear, themonth, withyear=True):
|
def __init__(self, *args, **kwargs):
|
||||||
# self.dmmonth = themonth
|
super().__init__(*args, **kwargs)
|
||||||
# super().formatmonth(self, theyear, themonth)
|
self.use_work_projects = False
|
||||||
|
self.task = None
|
||||||
|
|
||||||
def setcalmonth(self, month):
|
def setcalmonth(self, month):
|
||||||
self.dmmonth = month
|
self.dmmonth = month
|
||||||
@@ -29,6 +33,9 @@ class DMHTMLCalendar(calendar.HTMLCalendar):
|
|||||||
def settask(self, task):
|
def settask(self, task):
|
||||||
self.task = task
|
self.task = task
|
||||||
|
|
||||||
|
def set_work_projects_mode(self, enabled=True):
|
||||||
|
self.use_work_projects = enabled
|
||||||
|
|
||||||
def oneday(self, month, day):
|
def oneday(self, month, day):
|
||||||
current_year = datetime.today().year
|
current_year = datetime.today().year
|
||||||
start = datetime(self.dmyear, month, day).replace(
|
start = datetime(self.dmyear, month, day).replace(
|
||||||
@@ -38,7 +45,10 @@ class DMHTMLCalendar(calendar.HTMLCalendar):
|
|||||||
hour=23, minute=59, second=59, tzinfo=timezone
|
hour=23, minute=59, second=59, tzinfo=timezone
|
||||||
)
|
)
|
||||||
|
|
||||||
rows = get_period_totals(start, end, self.task)
|
if self.use_work_projects:
|
||||||
|
rows = get_work_period_totals(start, end)
|
||||||
|
else:
|
||||||
|
rows = get_period_totals(start, end, self.task)
|
||||||
|
|
||||||
returnstr = "<table class='totaltable'>"
|
returnstr = "<table class='totaltable'>"
|
||||||
for row in rows:
|
for row in rows:
|
||||||
@@ -75,7 +85,10 @@ class DMHTMLCalendar(calendar.HTMLCalendar):
|
|||||||
hour=23, minute=59, second=59, tzinfo=timezone
|
hour=23, minute=59, second=59, tzinfo=timezone
|
||||||
)
|
)
|
||||||
|
|
||||||
rows = get_period_totals(start, end, self.task)
|
if self.use_work_projects:
|
||||||
|
rows = get_work_period_totals(start, end)
|
||||||
|
else:
|
||||||
|
rows = get_period_totals(start, end, self.task)
|
||||||
|
|
||||||
print(rows)
|
print(rows)
|
||||||
|
|
||||||
@@ -117,6 +130,28 @@ class DMHTMLCalendar(calendar.HTMLCalendar):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dmbp.route("/workmonth")
|
||||||
|
@dmbp.route("/workmonth/<int:month>")
|
||||||
|
@dmbp.route("/workmonth/<int:month>/<int:year>")
|
||||||
|
def workmonth(month=None, year=None):
|
||||||
|
usemonth = datetime.today().month
|
||||||
|
useyear = datetime.today().year
|
||||||
|
|
||||||
|
if month:
|
||||||
|
usemonth = month
|
||||||
|
|
||||||
|
if year:
|
||||||
|
useyear = year
|
||||||
|
|
||||||
|
cal = DMHTMLCalendar(calendar.SATURDAY)
|
||||||
|
|
||||||
|
cal.set_work_projects_mode(True)
|
||||||
|
cal.setcalmonth(usemonth)
|
||||||
|
cal.setcalyear(useyear)
|
||||||
|
|
||||||
|
return render_template("calendar.html", content=cal.formatmonth(useyear, usemonth))
|
||||||
|
|
||||||
|
|
||||||
@dmbp.route("/month")
|
@dmbp.route("/month")
|
||||||
@dmbp.route("/month/<int:month>")
|
@dmbp.route("/month/<int:month>")
|
||||||
@dmbp.route("/month/<int:month>/<int:year>")
|
@dmbp.route("/month/<int:month>/<int:year>")
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ utctz = ZoneInfo("UTC")
|
|||||||
client = MongoClient()
|
client = MongoClient()
|
||||||
db = client.deskmeter
|
db = client.deskmeter
|
||||||
switches = db.switch
|
switches = db.switch
|
||||||
|
tasks = db.task
|
||||||
|
|
||||||
|
|
||||||
task_file = "/home/mariano/LETRAS/adm/task/main"
|
task_file = "/home/mariano/LETRAS/adm/task/main"
|
||||||
@@ -61,6 +62,70 @@ def read_and_extract(file_path):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_work_projects():
|
||||||
|
"""Get dict of work projects with their task IDs."""
|
||||||
|
work_tasks = list(
|
||||||
|
tasks.find(
|
||||||
|
{"path": {"$regex": "^work/"}, "task_id": {"$exists": True}},
|
||||||
|
{"path": 1, "task_id": 1, "_id": 0},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
projects = {}
|
||||||
|
for task in work_tasks:
|
||||||
|
# Extract project name from path like "work/cal" -> "cal"
|
||||||
|
path_parts = task["path"].split("/")
|
||||||
|
if len(path_parts) >= 2:
|
||||||
|
project_name = path_parts[1]
|
||||||
|
if project_name not in projects:
|
||||||
|
projects[project_name] = []
|
||||||
|
projects[project_name].append(task["task_id"])
|
||||||
|
|
||||||
|
return projects
|
||||||
|
|
||||||
|
|
||||||
|
def get_work_project_tasks():
|
||||||
|
"""Get comma-separated string of all task IDs under work/* paths."""
|
||||||
|
projects = get_work_projects()
|
||||||
|
all_task_ids = []
|
||||||
|
for task_ids in projects.values():
|
||||||
|
all_task_ids.extend(task_ids)
|
||||||
|
return ",".join(all_task_ids) if all_task_ids else None
|
||||||
|
|
||||||
|
|
||||||
|
def get_work_period_totals(start, end):
|
||||||
|
"""Get period totals grouped by work project."""
|
||||||
|
projects = get_work_projects()
|
||||||
|
combined_rows = []
|
||||||
|
|
||||||
|
for project_name, task_ids in projects.items():
|
||||||
|
if not task_ids:
|
||||||
|
continue
|
||||||
|
|
||||||
|
task_string = ",".join(task_ids)
|
||||||
|
rows = get_period_totals(start, end, task_string)
|
||||||
|
|
||||||
|
# Sum up all time for this project (looking for "Work" workspace)
|
||||||
|
total_seconds = 0
|
||||||
|
for row in rows:
|
||||||
|
if row["ws"] == "Work":
|
||||||
|
# Convert time string back to seconds to sum properly
|
||||||
|
time_parts = row["total"].split(":")
|
||||||
|
if len(time_parts) == 3:
|
||||||
|
hours, minutes, seconds = map(int, time_parts)
|
||||||
|
total_seconds += hours * 3600 + minutes * 60 + seconds
|
||||||
|
|
||||||
|
if total_seconds > 0:
|
||||||
|
combined_rows.append({
|
||||||
|
"ws": project_name,
|
||||||
|
"total": convert_seconds(total_seconds)
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sort by project name for consistency
|
||||||
|
combined_rows.sort(key=lambda x: x["ws"])
|
||||||
|
return combined_rows
|
||||||
|
|
||||||
|
|
||||||
def get_period_totals(start, end, task=None):
|
def get_period_totals(start, end, task=None):
|
||||||
task_query = {"$in": task.split(",")} if task else {}
|
task_query = {"$in": task.split(",")} if task else {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user