"""Query ClickUp 'to do' tasks tagged feb26 in OPT/LINKS/Content categories.""" import os import sys from datetime import datetime, timezone sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from dotenv import load_dotenv load_dotenv(os.path.join(os.path.dirname(__file__), "..", ".env")) from cheddahbot.clickup import ClickUpClient TOKEN = os.getenv("CLICKUP_API_TOKEN", "") SPACE_ID = os.getenv("CLICKUP_SPACE_ID", "") if not TOKEN or not SPACE_ID: print("ERROR: CLICKUP_API_TOKEN and CLICKUP_SPACE_ID must be set in .env") sys.exit(1) CATEGORIES = {"On Page Optimization", "Content Creation", "Link Building"} TAG_FILTER = "feb26" client = ClickUpClient(api_token=TOKEN, workspace_id="", task_type_field_name="Work Category") print(f"Querying ClickUp space {SPACE_ID} for 'to do' tasks...") tasks = client.get_tasks_from_space(SPACE_ID, statuses=["to do"]) client.close() print(f"Total 'to do' tasks found: {len(tasks)}") # Filter by feb26 tag tagged = [t for t in tasks if TAG_FILTER in [tag.lower() for tag in t.tags]] print(f"Tasks with '{TAG_FILTER}' tag: {len(tagged)}") # Filter by Work Category (OPT / LINKS / Content) filtered = [] for t in tagged: cat = (t.custom_fields.get("Work Category") or t.task_type or "").strip() if cat in CATEGORIES: filtered.append(t) if not filtered and tagged: # Show what categories exist so we can refine cats_found = set() for t in tagged: cats_found.add(t.custom_fields.get("Work Category") or t.task_type or "(none)") print(f"\nNo tasks matched categories {CATEGORIES}.") print(f"Work Categories found on feb26-tagged tasks: {cats_found}") print("\nShowing ALL feb26-tagged tasks instead:\n") filtered = tagged # Sort by due date (oldest first), tasks without due date go last def sort_key(t): if t.due_date: return int(t.due_date) return float("inf") filtered.sort(key=sort_key) # Take top 10 top = filtered[:10] # Format table def fmt_due(raw_due: str) -> str: if not raw_due: return "—" try: ts = int(raw_due) / 1000 return datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%m/%d") except (ValueError, OSError): return raw_due def fmt_customer(t) -> str: return t.custom_fields.get("Customer", "") or "—" print(f"\n{'#':<3} | {'ID':<12} | {'Keyword/Name':<45} | {'Cat':<15} | {'Due':<6} | {'Customer':<20} | Tags") print("-" * 120) for i, t in enumerate(top, 1): tags_str = ", ".join(t.tags) name = t.name[:45] cat = t.custom_fields.get("Work Category") or t.task_type or "—" print(f"{i:<3} | {t.id:<12} | {name:<45} | {cat:<15} | {fmt_due(t.due_date):<6} | {fmt_customer(t):<20} | {tags_str}") print(f"\nTotal shown: {len(top)} of {len(filtered)} matching tasks")