diff --git a/dmapp/dmcore/config.py b/dmapp/dmcore/config.py new file mode 100644 index 0000000..fad918b --- /dev/null +++ b/dmapp/dmcore/config.py @@ -0,0 +1,21 @@ +# dmapp/dmcore/config.py +import logging + +from pymongo import MongoClient + +# Logging configuration +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", +) +logger = logging.getLogger(__name__) + +# MongoDB configuration +client = MongoClient() +db = client.deskmeter + +# Collections +switches = db.switch +states = db.state +tasks = db.task diff --git a/dmapp/dmcore/main.py b/dmapp/dmcore/main.py index e9f244b..aa53c91 100644 --- a/dmapp/dmcore/main.py +++ b/dmapp/dmcore/main.py @@ -4,29 +4,21 @@ import subprocess import time from pprint import pprint -import task import state -from pymongo import MongoClient +import task +from config import logger, switches from zoneinfo import ZoneInfo -client = MongoClient() +desktops = ("Plan", "Think", "Work", "Other", "Away", "Work", "Work") +work_desktops = {2: "default", 5: "dlt", 6: "vhs"} + +unlabeled = "Away" def now(): return datetime.datetime.now(ZoneInfo("America/Argentina/Buenos_Aires")) -db = client.deskmeter -switches = db.switch -dailies = db.daily - - -desktops = ("Plan", "Think", "Work", "Other", "Away", "Work", "Work") - - -unlabeled = "Away" - - def active_workspace(): workspaces = ( subprocess.check_output(["wmctrl", "-d"]) @@ -38,8 +30,6 @@ def active_workspace(): for workspace in workspaces: if workspace[3] == "*": return int(workspace[0]) - return None - return None def desktop(workspace_index): @@ -49,8 +39,12 @@ def desktop(workspace_index): return unlabeled +task.read_and_extract(None) +state.init_work_state(work_desktops) + + current_workspace = active_workspace() -current_task = state.get_current_task() +current_task = state.retrieve("current").get("task") last_switch_time = now() switch = { @@ -63,13 +57,18 @@ switch = { switches.insert_one(switch) while True: - current_task = state.get_current_task() + current_task = state.retrieve("current").get("task") current_workspace = active_workspace() - state.update_current_workspace(current_workspace) - - + state.save("current", workspace=current_workspace) last_doc = switches.find_one(sort=[("_id", -1)]) + + # work workflow + + if current_workspace in work_desktops.keys(): + pass + + # regular flow if ( last_doc["workspace"] == desktop(current_workspace) and last_doc["task"] == current_task diff --git a/dmapp/dmcore/state.py b/dmapp/dmcore/state.py index 99f21ca..5332530 100644 --- a/dmapp/dmcore/state.py +++ b/dmapp/dmcore/state.py @@ -1,35 +1,47 @@ -from pymongo import MongoClient - -client = MongoClient() -db = client.deskmeter -state = db.state +from config import logger, states, tasks -def update_current_task(task): - state.update_one( - {"_id": "current_task"}, - {"$set": {"task": task}}, - upsert=True, - ) +def save(doc_id: str, *, task: str | None = None, workspace: str | None = None) -> None: + """ + Upsert a document with _id=doc_id, setting any of the provided fields. + Leave fields you don’t pass unchanged. + """ + updates: dict = {} + if task is not None: + updates["task"] = task + if workspace is not None: + updates["workspace"] = workspace + if updates: + states.update_one( + {"_id": doc_id}, + {"$set": updates}, + upsert=True, + ) -def update_current_workspace(workspace): - state.update_one( - {"_id": "current_workspace"}, - {"$set": {"workspace": workspace}}, - upsert=True, - ) +def retrieve(doc_id: str) -> dict[str, str | None]: + """ + Fetches the document with _id=doc_id and returns its 'task' and 'workspace'. + If the document doesn’t exist, both will be None. + """ + doc = states.find_one({"_id": doc_id}) + return { + "task": doc.get("task") if doc else None, + "workspace": doc.get("workspace") if doc else None, + } -def get_current_task(): - current_task = state.find_one({"_id": "current_task"}) - if current_task: - return current_task.get("task") - return None - - -def get_current_workspace(): - current_workspace = state.find_one({"_id": "current_workspace"}) - if current_workspace: - return current_workspace.get("workspace") - return None +def init_work_state(wd: dict): + """ + init work states with default values + """ + if not states.find_one({"_id": "work"}): + states.insert_one( + { + "_id": "work", + **{ + wd[k]: tasks.find_one({"path": f"work/{wd[k]}"})["task_id"] + for k in wd + }, + } + ) diff --git a/dmapp/dmcore/task.py b/dmapp/dmcore/task.py index 8a80ecb..a542aff 100644 --- a/dmapp/dmcore/task.py +++ b/dmapp/dmcore/task.py @@ -4,11 +4,7 @@ from typing import Optional import state from bson import ObjectId -from pymongo import MongoClient - -client = MongoClient() -db = client.deskmeter -tasks = db.task +from config import logger, tasks task_file = "/home/mariano/wdir/def/deskmeter/dmapp/dmcore/sample_task_file" @@ -16,14 +12,13 @@ task_file = "/home/mariano/wdir/def/deskmeter/dmapp/dmcore/sample_task_file" def parse_line(line: str) -> tuple[Optional[str], Optional[str]]: """Parse a task line to extract task name and ID.""" line = line.strip() + if not line: return None, None - # Split by | and check if we have an ID part parts = line.split("|") if len(parts) > 1: task_name = parts[0].strip() - # Take everything after | and clean it up task_id = parts[1].split()[0].strip() return task_name, task_id @@ -64,6 +59,15 @@ def file_to_db(filepath: str): seen_paths.add(full_path) + tasks.createIndex( + {"path": 1}, + { + name: "idx_tasks_path_ci", + background: true, + collation: {locale: "es", strength: 1}, + }, + ) + def format_task_line( path_parts: list, indent_level: int, task_id: str, current_task: str @@ -79,7 +83,7 @@ def format_task_line( def db_to_file_as_is(filepath: str): """Write tasks from MongoDB to file exactly as they were read.""" - current_task = state.get_current_task() + current_task = state.retrieve("current").get("task") all_tasks = list(tasks.find()) with open(filepath, "w") as f: @@ -95,9 +99,13 @@ def db_to_file_as_is(filepath: str): f.write(f"{line}\n") +def get_all_tasks(prefix): + return list(tasks.find({"path": {"$ne": ""}}).sort("path", 1)) + + def db_to_file_consolidated(filepath: str): """Write tasks from MongoDB to file as a consolidated tree.""" - current_task = state.get_current_task() + current_task = state.retrieve("current").get("task") all_tasks = list(tasks.find({"path": {"$ne": ""}}).sort("path", 1)) with open(filepath, "w") as f: @@ -128,15 +136,15 @@ def extract(line: str) -> Optional[str]: # Extract everything between | and * and strip spaces id_part = line[pipe_index + 1 : -1].strip() if len(id_part) == 8: - state.update_current_task(id_part) + state.save("current", task=id_part) return id_part return None def read_and_extract(file_path: str) -> Optional[str]: """Read file and update state if current task is found.""" - if not Path(file_path).exists(): - return None + if file_path is None: + file_path = task_file with open(file_path, "r") as file: for line in file: