"""Query ClickUp 'to do' tasks tagged feb26 in OPT/LINKS/Content categories.""" import sys from pathlib import Path from datetime import datetime, timezone # Add project root to path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from cheddahbot.config import load_config from cheddahbot.clickup import ClickUpClient def ms_to_date(ms_str: str) -> str: """Convert Unix-ms timestamp string to YYYY-MM-DD.""" if not ms_str: return "—" try: ts = int(ms_str) / 1000 return datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%Y-%m-%d") except (ValueError, OSError): return "—" def main(): cfg = load_config() if not cfg.clickup.api_token or not cfg.clickup.space_id: print("ERROR: CLICKUP_API_TOKEN or CLICKUP_SPACE_ID not set.") return client = ClickUpClient( api_token=cfg.clickup.api_token, workspace_id=cfg.clickup.workspace_id, task_type_field_name=cfg.clickup.task_type_field_name, ) # Step 1: Get folders, find OPT/LINKS/Content target_folders = {"opt", "links", "content"} try: folders = client.get_folders(cfg.clickup.space_id) except Exception as e: print(f"ERROR fetching folders: {e}") client.close() return print(f"All folders: {[f['name'] for f in folders]}") matched_lists = [] # (list_id, list_name, folder_name) for folder in folders: if folder["name"].lower() in target_folders: for lst in folder["lists"]: matched_lists.append((lst["id"], lst["name"], folder["name"])) if not matched_lists: print(f"No folders matching {target_folders}. Falling back to full space scan.") try: tasks = client.get_tasks_from_space(cfg.clickup.space_id, statuses=["to do"]) finally: client.close() else: print(f"Querying lists: {[(ln, fn) for _, ln, fn in matched_lists]}") tasks = [] for list_id, list_name, folder_name in matched_lists: try: batch = client.get_tasks(list_id, statuses=["to do"]) # Stash folder name on each task for display for t in batch: t._folder = folder_name tasks.extend(batch) except Exception as e: print(f" Error fetching {list_name}: {e}") client.close() print(f"Total 'to do' tasks from target folders: {len(tasks)}") # Filter by "feb26" tag (case-insensitive) tagged = [t for t in tasks if any(tag.lower() == "feb26" for tag in t.tags)] if not tagged: print(f"No 'to do' tasks with 'feb26' tag found.") all_tags = set() for t in tasks: all_tags.update(t.tags) print(f"Tags found across all to-do tasks: {sorted(all_tags)}") return filtered = tagged # Sort by due date (oldest first), tasks without due date go last def sort_key(t): if t.due_date: return (0, int(t.due_date)) return (1, 0) filtered.sort(key=sort_key) # Take top 10 top10 = filtered[:10] # Build table print(f"\n## ClickUp 'to do' — feb26 tag — OPT/LINKS/Content ({len(filtered)} total, showing top 10)\n") print(f"{'#':<3} | {'ID':<12} | {'Keyword/Name':<40} | {'Due':<12} | {'Customer':<20} | Tags") print(f"{'—'*3} | {'—'*12} | {'—'*40} | {'—'*12} | {'—'*20} | {'—'*15}") for i, t in enumerate(top10, 1): customer = t.custom_fields.get("Customer", "") or "—" due = ms_to_date(t.due_date) tags = ", ".join(t.tags) if t.tags else "—" name = t.name[:38] + ".." if len(t.name) > 40 else t.name print(f"{i:<3} | {t.id:<12} | {name:<40} | {due:<12} | {customer:<20} | {tags}") print(f"\nCategory breakdown:") from collections import Counter cats = Counter(t.task_type for t in filtered) for cat, count in cats.most_common(): print(f" {cat or '(none)'}: {count}") if __name__ == "__main__": main()