Fixed tags management

This commit is contained in:
2025-12-30 12:53:42 +01:00
parent 22634b8290
commit 91e1a83bf0
+40 -44
View File
@@ -109,27 +109,6 @@ def chunks(lst: List[Any], n: int) -> Iterable[List[Any]]:
yield lst[i : i + n] yield lst[i : i + n]
def _sanitize_tags(tags: Optional[List[str]]) -> Optional[List[str]]:
if not tags:
return None
clean: List[str] = []
for t in tags:
if t is None:
continue
s = str(t).strip()
if not s or s.lower() in ("undefined", "null", "none"):
continue
clean.append(s)
# dedup preserving order
seen = set()
out = []
for s in clean:
if s not in seen:
seen.add(s)
out.append(s)
return out or None
def _valid_name(x: Any) -> Optional[str]: def _valid_name(x: Any) -> Optional[str]:
if x is None: if x is None:
return None return None
@@ -193,6 +172,28 @@ def build_tududi_description_from_todoist(task: Dict[str, Any], task_name: str)
return "\n\n".join(parts).strip() return "\n\n".join(parts).strip()
def build_tududi_tag_objects(tag_names: List[str], tag_by_name: Dict[str, Dict[str, Any]]) -> List[Dict[str, str]]:
objs: List[Dict[str, str]] = []
seen = set()
for n in tag_names or []:
key = str(n).strip()
if not key or key in seen:
continue
seen.add(key)
t = tag_by_name.get(key)
if not t:
continue
uid = t.get("uid")
name = t.get("name") or key
if not uid or not name:
continue
objs.append({"name": name, "uid": uid})
return objs
# ---------------------------- # ----------------------------
# Todoist client (API v1) # Todoist client (API v1)
# ---------------------------- # ----------------------------
@@ -286,7 +287,7 @@ class TududiClient:
password: Optional[str] = None, password: Optional[str] = None,
timeout: int = 60, timeout: int = 60,
dry_run: bool = False, dry_run: bool = False,
request_sleep: float = 0.25, request_sleep: float = 0.15,
) -> None: ) -> None:
self.base_url = base_url.rstrip("/") self.base_url = base_url.rstrip("/")
self.timeout = timeout self.timeout = timeout
@@ -343,7 +344,7 @@ class TududiClient:
print(f"[DRY_RUN] POST {path} payload={payload}") print(f"[DRY_RUN] POST {path} payload={payload}")
return {"_dry_run": True} return {"_dry_run": True}
if payload is not None and isinstance(payload, dict): if payload is not None and isinstance(payload, dict):
print(f"[DEBUG] POST {path} payload.Tags={payload.get('Tags')}") print(f"[DEBUG] POST {path} payload.Tags={payload.get('Tags') if isinstance(payload, dict) else None}")
r = self.s.post(url, data=json.dumps(payload or {}), timeout=self.timeout) r = self.s.post(url, data=json.dumps(payload or {}), timeout=self.timeout)
# 429 -> retry # 429 -> retry
@@ -444,7 +445,7 @@ class TududiClient:
project_id: Optional[int] = None, project_id: Optional[int] = None,
due_date: Optional[str] = None, due_date: Optional[str] = None,
priority: Optional[str] = None, priority: Optional[str] = None,
tags: Optional[List[Dict[str, str]]] = None, tag_objs: Optional[List[Dict[str, str]]] = None,
description: Optional[str] = None, description: Optional[str] = None,
note: Optional[str] = None, note: Optional[str] = None,
parent_task_id: Optional[int] = None, parent_task_id: Optional[int] = None,
@@ -461,24 +462,10 @@ class TududiClient:
if priority: if priority:
payload["priority"] = priority payload["priority"] = priority
tags = _sanitize_tags(tags)
if tags: if tag_objs:
clean_tags: List[Dict[str, str]] = [] payload["Tags"] = tag_objs
for t in tags:
if not isinstance(t, dict):
continue
name = str(t.get("name") or "").strip()
uid = str(t.get("uid") or "").strip()
if not name or name.lower() in ("undefined", "null", "none"):
continue
if not uid or uid.lower() in ("undefined", "null", "none"):
continue
clean_tags.append({"name": name, "uid": uid})
if clean_tags:
payload["Tags"] = clean_tags
# Tududi spesso usa "note" (tu lhai mostrato), non "description"
if note: if note:
payload["note"] = note payload["note"] = note
if description: if description:
@@ -835,6 +822,8 @@ def main() -> None:
return None return None
return project_map.get(str(pid)) return project_map.get(str(pid))
def get_tags_for_task(task: Dict[str, Any]) -> List[Dict[str, str]]: def get_tags_for_task(task: Dict[str, Any]) -> List[Dict[str, str]]:
lbls = task.get("labels") or task.get("label_ids") or task.get("labelIds") or [] lbls = task.get("labels") or task.get("label_ids") or task.get("labelIds") or []
names: List[str] = [] names: List[str] = []
@@ -889,8 +878,7 @@ def main() -> None:
due = normalize_due(task) due = normalize_due(task)
prio = map_priority(task.get("priority")) prio = map_priority(task.get("priority"))
project_uid = get_project_uid_for_task(task) project_uid = get_project_uid_for_task(task)
tags = get_tags_for_task(task)
# Tududi note: Todoist link + Todoist description # Tududi note: Todoist link + Todoist description
tududi_description = build_tududi_description_from_todoist(task, name) tududi_description = build_tududi_description_from_todoist(task, name)
@@ -903,12 +891,20 @@ def main() -> None:
is_completed = is_done_map.get(tid, False) is_completed = is_done_map.get(tid, False)
completed_at = task.get("completed_at") or task.get("completedAt") completed_at = task.get("completed_at") or task.get("completedAt")
tag_objs = get_tags_for_task(task) # già [{"name":..., "uid":...}]
if tag_objs:
print(f"[DEBUG] task={tid} tags_obj={tag_objs}")
else:
raw_lbls = task.get("labels") or task.get("label_ids") or task.get("labelIds")
print(f"[DEBUG] task={tid} NO TAGS. raw_labels={raw_lbls}")
created = tud.create_task( created = tud.create_task(
name=name, name=name,
project_id=project_uid, project_id=project_uid,
due_date=due, due_date=due,
priority=prio, priority=prio,
tags=tags if tags else None, tag_objs=tag_objs if tag_objs else None,
description=tududi_description, description=tududi_description,
note=tududi_description, note=tududi_description,
parent_task_id=tud_parent_id, parent_task_id=tud_parent_id,