Files
deskmeter/dmold/dmweb/dm.py
2025-12-29 14:12:46 -03:00

284 lines
9.0 KiB
Python

from datetime import datetime, timedelta
from flask import Blueprint, render_template, jsonify
from .get_period_times import get_period_totals, task_or_none, timezone, get_work_period_totals, get_current_task_info, convert_seconds, get_task_time_seconds, get_task_blocks_calendar, get_raw_switches
dmbp = Blueprint("deskmeter", __name__, url_prefix="/", template_folder="templates")
@dmbp.route("/favicon.ico")
def favicon():
return "", 204 # No Content
@dmbp.route("/calendar")
@dmbp.route("/calendar/<string:scope>")
@dmbp.route("/calendar/<string:scope>/<int:year>/<int:month>/<int:day>")
def calendar_view(scope="daily", year=None, month=None, day=None):
"""
Google Calendar-style view showing task blocks at their actual times.
"""
task = None
if not year:
year = datetime.today().year
if not month:
month = datetime.today().month
if not day:
day = datetime.today().day
base_date = datetime(year, month, day).replace(hour=0, minute=0, second=0, tzinfo=timezone)
if scope == "daily":
start = base_date
end = base_date.replace(hour=23, minute=59, second=59)
blocks = get_task_blocks_calendar(start, end, task, min_block_seconds=60)
prev_date = base_date - timedelta(days=1)
next_date = base_date + timedelta(days=1)
days = [base_date]
elif scope == "weekly":
start = base_date - timedelta(days=base_date.weekday())
end = start + timedelta(days=6, hours=23, minutes=59, seconds=59)
blocks = get_task_blocks_calendar(start, end, task, min_block_seconds=300)
prev_date = start - timedelta(days=7)
next_date = start + timedelta(days=7)
days = [start + timedelta(days=i) for i in range(7)]
elif scope == "monthly":
start = base_date.replace(day=1)
if month == 12:
end = datetime(year + 1, 1, 1, tzinfo=timezone) - timedelta(seconds=1)
else:
end = datetime(year, month + 1, 1, tzinfo=timezone) - timedelta(seconds=1)
blocks = get_task_blocks_calendar(start, end, task, min_block_seconds=600)
if month == 1:
prev_date = datetime(year - 1, 12, 1, tzinfo=timezone)
else:
prev_date = datetime(year, month - 1, 1, tzinfo=timezone)
if month == 12:
next_date = datetime(year + 1, 1, 1, tzinfo=timezone)
else:
next_date = datetime(year, month + 1, 1, tzinfo=timezone)
days = []
current = start
while current <= end:
days.append(current)
current += timedelta(days=1)
else:
scope = "daily"
start = base_date
end = base_date.replace(hour=23, minute=59, second=59)
blocks = get_task_blocks_calendar(start, end, task, min_block_seconds=60)
prev_date = base_date - timedelta(days=1)
next_date = base_date + timedelta(days=1)
days = [base_date]
return render_template(
"calendar_view.html",
scope=scope,
blocks=blocks,
start=start,
end=end,
base_date=base_date,
prev_date=prev_date,
next_date=next_date,
days=days,
auto_refresh=False
)
@dmbp.route("/switches")
@dmbp.route("/switches/<string:scope>")
@dmbp.route("/switches/<string:scope>/<int:year>/<int:month>/<int:day>")
def switches_view(scope="daily", year=None, month=None, day=None):
"""
Raw switches view showing all switch documents.
"""
task = None
if not year:
year = datetime.today().year
if not month:
month = datetime.today().month
if not day:
day = datetime.today().day
base_date = datetime(year, month, day).replace(hour=0, minute=0, second=0, tzinfo=timezone)
if scope == "daily":
start = base_date
end = base_date.replace(hour=23, minute=59, second=59)
prev_date = base_date - timedelta(days=1)
next_date = base_date + timedelta(days=1)
elif scope == "weekly":
start = base_date - timedelta(days=base_date.weekday())
end = start + timedelta(days=6, hours=23, minutes=59, seconds=59)
prev_date = start - timedelta(days=7)
next_date = start + timedelta(days=7)
elif scope == "monthly":
start = base_date.replace(day=1)
if month == 12:
end = datetime(year + 1, 1, 1, tzinfo=timezone) - timedelta(seconds=1)
else:
end = datetime(year, month + 1, 1, tzinfo=timezone) - timedelta(seconds=1)
if month == 1:
prev_date = datetime(year - 1, 12, 1, tzinfo=timezone)
else:
prev_date = datetime(year, month - 1, 1, tzinfo=timezone)
if month == 12:
next_date = datetime(year + 1, 1, 1, tzinfo=timezone)
else:
next_date = datetime(year, month + 1, 1, tzinfo=timezone)
else:
scope = "daily"
start = base_date
end = base_date.replace(hour=23, minute=59, second=59)
prev_date = base_date - timedelta(days=1)
next_date = base_date + timedelta(days=1)
raw_switches = get_raw_switches(start, end, task)
return render_template(
"switches_view.html",
scope=scope,
switches=raw_switches,
start=start,
end=end,
base_date=base_date,
prev_date=prev_date,
next_date=next_date,
auto_refresh=False
)
@dmbp.route("/")
@dmbp.route("/<string:task>")
def index(task=None):
"""
Show total time used in each desktop for today
"""
task = task_or_none(task)
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_period_totals(start, end, task)
# Get current task info
current_task_id, current_task_path = get_current_task_info()
current_task_time = None
if current_task_id:
total_seconds = get_task_time_seconds(start, end, current_task_id)
if total_seconds > 0:
current_task_time = convert_seconds(total_seconds)
return render_template("main.html", rows=rows, current_task_path=current_task_path, current_task_time=current_task_time, auto_refresh=True)
@dmbp.route("/api/current_task")
def api_current_task():
"""
JSON API endpoint returning current task information
"""
current_task_id, current_task_path = get_current_task_info()
return jsonify({
"task_id": current_task_id,
"task_path": current_task_path or "no task"
})
@dmbp.route("/api/today")
@dmbp.route("/api/today/<string:task>")
def api_today(task=None):
"""
HTML fragment API endpoint for today's data (for AJAX updates)
"""
task = task_or_none(task)
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_period_totals(start, end, task)
# Get current task info
current_task_id, current_task_path = get_current_task_info()
current_task_time = None
if current_task_id:
total_seconds = get_task_time_seconds(start, end, current_task_id)
if total_seconds > 0:
current_task_time = convert_seconds(total_seconds)
return render_template("main_content.html", rows=rows, current_task_path=current_task_path, current_task_time=current_task_time)
@dmbp.route("/day/<int:month>/<int:day>")
@dmbp.route("/day/<string:task>/<int:month>/<int:day>")
def oneday(
month,
day,
task=None,
):
task = task_or_none(task)
start = datetime(2025, month, day).replace(
hour=0, minute=0, second=0, tzinfo=timezone
)
end = datetime(2025, month, day).replace(
hour=23, minute=59, second=59, tzinfo=timezone
)
rows = get_period_totals(start, end)
return render_template("pages.html", rows=rows, auto_refresh=True)
@dmbp.route("/period/<start>/<end>")
def period(start, end):
start = datetime(*map(int, start.split("-"))).replace(
hour=0, minute=0, second=0, tzinfo=timezone
)
end = datetime(*map(int, end.split("-"))).replace(
hour=23, minute=59, second=59, tzinfo=timezone
)
rows = get_period_totals(start, end)
return render_template("pages.html", rows=rows, auto_refresh=True)
@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)
return render_template("main.html", rows=rows, auto_refresh=False)
@dmbp.route("/totals")
@dmbp.route("/totals/<string:task>")
def totals(task=None):
"""
Show total time used in each desktop for all time
"""
task = task_or_none(task)
start = datetime(2020, 1, 1).replace(hour=0, minute=0, second=0, tzinfo=timezone)
end = datetime(2030, 1, 1).replace(hour=23, minute=59, second=59, tzinfo=timezone)
rows = get_period_totals(start, end)
return render_template("pages.html", rows=rows, auto_refresh=True)