CheddahBot/scripts/query_feb26.py

103 lines
3.1 KiB
Python

"""Query ClickUp 'to do' tasks tagged 'feb26' in OPT/LINKS/Content categories."""
from __future__ import annotations
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
_root = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(_root))
from dotenv import load_dotenv
load_dotenv(_root / ".env")
from cheddahbot.clickup import ClickUpClient
API_TOKEN = os.environ.get("CLICKUP_API_TOKEN", "")
SPACE_ID = os.environ.get("CLICKUP_SPACE_ID", "")
if not API_TOKEN:
sys.exit("ERROR: CLICKUP_API_TOKEN env var is required")
if not SPACE_ID:
sys.exit("ERROR: CLICKUP_SPACE_ID env var is required")
# Work Category values to include (case-insensitive partial match)
CATEGORY_FILTERS = ["opt", "link", "content"]
TAG_FILTER = "feb26"
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 ms_str
def main() -> None:
client = ClickUpClient(api_token=API_TOKEN, task_type_field_name="Work Category")
print(f"Fetching 'to do' tasks from space {SPACE_ID} ...")
tasks = client.get_tasks_from_overall_lists(SPACE_ID, statuses=["to do"])
print(f"Total 'to do' tasks: {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)}")
# Show all Work Category values for debugging
categories = set()
for t in tagged:
wc = t.custom_fields.get("Work Category", "") or ""
categories.add(wc)
print(f"Work Categories found: {categories}")
# Filter by OPT/LINKS/Content categories
filtered = []
for t in tagged:
wc = str(t.custom_fields.get("Work Category", "") or "").lower()
if any(cat in wc for cat in CATEGORY_FILTERS):
filtered.append(t)
print(f"After category filter (OPT/LINKS/Content): {len(filtered)}")
# Sort by due date (oldest first), tasks with no due date go last
def sort_key(t):
if t.due_date:
try:
return (0, int(t.due_date))
except ValueError:
return (1, 0)
return (2, 0)
filtered.sort(key=sort_key)
# Top 10
top10 = filtered[:10]
# Print table
print(f"\n{'#':>3} | {'ID':>11} | {'Keyword/Name':<45} | {'Due':>10} | {'Customer':<20} | Tags")
print("-" * 120)
for i, t in enumerate(top10, 1):
customer = t.custom_fields.get("Customer", "") or ""
due = ms_to_date(t.due_date)
wc = t.custom_fields.get("Work Category", "") or ""
tags_str = ", ".join(t.tags)
name_display = t.name[:45] if len(t.name) > 45 else t.name
print(f"{i:>3} | {t.id:>11} | {name_display:<45} | {due:>10} | {customer:<20} | {tags_str}")
if not top10:
print(" (no matching tasks found)")
print(f"\n--- {len(filtered)} total matching tasks, showing top {len(top10)} (oldest first) ---")
if __name__ == "__main__":
main()