CheddahBot/scripts/clickup_feb26.py

95 lines
3.3 KiB
Python

"""Query ClickUp 'to do' tasks tagged feb26 in OPT/LINKS/Content categories."""
import sys
from datetime import datetime, timezone
from pathlib import Path
sys.stdout.reconfigure(line_buffering=True)
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from cheddahbot.config import load_config
from cheddahbot.clickup import ClickUpClient
CATEGORY_PREFIXES = ("opt", "link", "content", "ai content")
TAG_FILTER = "feb26"
def ms_to_date(ms_str: str) -> str:
if not ms_str:
return ""
try:
ts = int(ms_str) / 1000
return datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%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,
)
try:
# Fetch all 'to do' tasks across the space
tasks = client.get_tasks_from_space(cfg.clickup.space_id, statuses=["to do"])
# Filter by feb26 tag
tagged = [t for t in tasks if TAG_FILTER in [tag.lower() for tag in t.tags]]
if not tagged:
all_tags = set()
for t in tasks:
all_tags.update(t.tags)
print(f"No tasks with tag '{TAG_FILTER}'. Tags seen: {sorted(all_tags)}")
print(f"Total 'to do' tasks found: {len(tasks)}")
return
# Filter to OPT/LINKS/Content categories (by task name, Work Category, or list name)
def is_target_category(t):
name_lower = t.name.lower().strip()
wc = (t.custom_fields.get("Work Category") or "").lower()
ln = (t.list_name or "").lower()
for prefix in CATEGORY_PREFIXES:
if name_lower.startswith(prefix) or prefix in wc or prefix in ln:
return True
return False
filtered = [t for t in tagged if is_target_category(t)]
skipped = [t for t in tagged if not is_target_category(t)]
# Sort by due date (oldest first), tasks with no due date go last
filtered.sort(key=lambda t: int(t.due_date) if t.due_date else float("inf"))
top = filtered[:10]
# Build table
print(f"feb26-tagged 'to do' tasks — OPT / LINKS / Content (top 10, oldest first)")
print(f"\n{'#':>2} | {'ID':<11} | {'Keyword/Name':<50} | {'Due':<6} | {'Customer':<25} | Tags")
print("-" * 120)
for i, t in enumerate(top, 1):
customer = t.custom_fields.get("Customer", "") or ""
due = ms_to_date(t.due_date)
tags = ", ".join(t.tags)
name = t.name[:50]
print(f"{i:>2} | {t.id:<11} | {name:<50} | {due:<6} | {customer:<25} | {tags}")
print(f"\nShowing {len(top)} of {len(filtered)} OPT/LINKS/Content tasks ({len(tagged)} total feb26-tagged).")
if skipped:
print(f"\nSkipped {len(skipped)} non-OPT/LINKS/Content tasks:")
for t in skipped:
print(f" - {t.name} ({t.id})")
finally:
client.close()
if __name__ == "__main__":
main()