Enhance get_todos method to handle pagination in BasecampClient

Updated the get_todos method to retrieve all todos from a todolist by handling pagination transparently. The method now aggregates todos across multiple pages and updates the README to reflect this change.
This commit is contained in:
George Antonopoulos
2025-08-28 14:00:53 +01:00
parent 632a5769b0
commit c3c96712e6
2 changed files with 31 additions and 7 deletions

View File

@@ -154,7 +154,7 @@ Once configured, you can use these tools in Cursor:
- `get_projects` - Get all Basecamp projects
- `get_project` - Get details for a specific project
- `get_todolists` - Get todo lists for a project
- `get_todos` - Get todos from a todo list
- `get_todos` - Get todos from a todo list (returns all pages; handles Basecamp pagination transparently)
- `search_basecamp` - Search across projects, todos, and messages
- `get_comments` - Get comments for a Basecamp item
- `get_campfire_lines` - Get recent messages from a Basecamp campfire

View File

@@ -144,13 +144,37 @@ class BasecampClient:
# To-do methods
def get_todos(self, project_id, todolist_id):
"""Get all todos in a todolist."""
response = self.get(f'buckets/{project_id}/todolists/{todolist_id}/todos.json')
if response.status_code == 200:
return response.json()
else:
"""Get all todos in a todolist, handling pagination.
Basecamp paginates list endpoints (commonly 15 items per page). This
implementation follows pagination via the `page` query parameter and
the HTTP `Link` header if present, aggregating all pages before
returning the combined list.
"""
endpoint = f'buckets/{project_id}/todolists/{todolist_id}/todos.json'
all_todos = []
page = 1
while True:
response = self.get(endpoint, params={"page": page})
if response.status_code != 200:
raise Exception(f"Failed to get todos: {response.status_code} - {response.text}")
page_items = response.json() or []
all_todos.extend(page_items)
# Check for next page using Link header or by empty result
link_header = response.headers.get("Link", "")
has_next = 'rel="next"' in link_header if link_header else False
if not page_items or not has_next:
break
page += 1
return all_todos
def get_todo(self, todo_id):
"""Get a specific todo."""
response = self.get(f'todos/{todo_id}.json')