Fixed tags management
This commit is contained in:
@@ -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 l’hai 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,
|
||||||
|
|||||||
Reference in New Issue
Block a user