diff options
Diffstat (limited to 'internal/api/trello.go')
| -rw-r--r-- | internal/api/trello.go | 111 |
1 files changed, 100 insertions, 11 deletions
diff --git a/internal/api/trello.go b/internal/api/trello.go index c78ebc8..5b87e30 100644 --- a/internal/api/trello.go +++ b/internal/api/trello.go @@ -6,7 +6,9 @@ import ( "fmt" "io" "net/http" + "net/url" "sort" + "strings" "sync" "time" @@ -21,14 +23,16 @@ const ( type TrelloClient struct { apiKey string token string + baseURL string httpClient *http.Client } // NewTrelloClient creates a new Trello API client func NewTrelloClient(apiKey, token string) *TrelloClient { return &TrelloClient{ - apiKey: apiKey, - token: token, + apiKey: apiKey, + token: token, + baseURL: trelloBaseURL, httpClient: &http.Client{ Timeout: 30 * time.Second, }, @@ -60,7 +64,7 @@ type trelloListResponse struct { // GetBoards fetches all boards for the authenticated user func (c *TrelloClient) GetBoards(ctx context.Context) ([]models.Board, error) { - url := fmt.Sprintf("%s/members/me/boards?key=%s&token=%s", trelloBaseURL, c.apiKey, c.token) + url := fmt.Sprintf("%s/members/me/boards?key=%s&token=%s", c.baseURL, c.apiKey, c.token) req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { @@ -99,7 +103,7 @@ func (c *TrelloClient) GetBoards(ctx context.Context) ([]models.Board, error) { // GetCards fetches all cards for a specific board func (c *TrelloClient) GetCards(ctx context.Context, boardID string) ([]models.Card, error) { - url := fmt.Sprintf("%s/boards/%s/cards?key=%s&token=%s", trelloBaseURL, boardID, c.apiKey, c.token) + url := fmt.Sprintf("%s/boards/%s/cards?key=%s&token=%s", c.baseURL, boardID, c.apiKey, c.token) req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { @@ -156,7 +160,7 @@ func (c *TrelloClient) GetCards(ctx context.Context, boardID string) ([]models.C // getLists fetches lists for a board and returns a map of list ID to name func (c *TrelloClient) getLists(ctx context.Context, boardID string) (map[string]string, error) { - url := fmt.Sprintf("%s/boards/%s/lists?key=%s&token=%s", trelloBaseURL, boardID, c.apiKey, c.token) + url := fmt.Sprintf("%s/boards/%s/lists?key=%s&token=%s", c.baseURL, boardID, c.apiKey, c.token) req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { @@ -256,14 +260,99 @@ func (c *TrelloClient) GetBoardsWithCards(ctx context.Context) ([]models.Board, return boards, nil } -// CreateCard creates a new card (for Phase 2) +// CreateCard creates a new card in the specified list func (c *TrelloClient) CreateCard(ctx context.Context, listID, name, description string, dueDate *time.Time) (*models.Card, error) { - // This will be implemented in Phase 2 - return nil, fmt.Errorf("not implemented yet") + // Prepare request payload + data := url.Values{} + data.Set("key", c.apiKey) + data.Set("token", c.token) + data.Set("idList", listID) + data.Set("name", name) + + if description != "" { + data.Set("desc", description) + } + + if dueDate != nil { + data.Set("due", dueDate.Format(time.RFC3339)) + } + + // Create POST request + reqURL := c.baseURL + "/cards" + req, err := http.NewRequestWithContext(ctx, "POST", reqURL, strings.NewReader(data.Encode())) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + // Execute request + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to create card: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("trello API error (status %d): %s", resp.StatusCode, string(body)) + } + + // Decode response + var apiCard trelloCardResponse + if err := json.NewDecoder(resp.Body).Decode(&apiCard); err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } + + // Convert to our model + card := &models.Card{ + ID: apiCard.ID, + Name: apiCard.Name, + ListID: apiCard.IDList, + URL: apiCard.URL, + } + + // Parse due date if present + if apiCard.Due != nil && *apiCard.Due != "" { + parsedDate, err := time.Parse(time.RFC3339, *apiCard.Due) + if err == nil { + card.DueDate = &parsedDate + } + } + + return card, nil } -// UpdateCard updates a card (for Phase 2) +// UpdateCard updates a card with the specified changes func (c *TrelloClient) UpdateCard(ctx context.Context, cardID string, updates map[string]interface{}) error { - // This will be implemented in Phase 2 - return fmt.Errorf("not implemented yet") + // Prepare request payload + data := url.Values{} + data.Set("key", c.apiKey) + data.Set("token", c.token) + + // Add updates to payload + for key, value := range updates { + data.Set(key, fmt.Sprintf("%v", value)) + } + + // Create PUT request + reqURL := fmt.Sprintf("%s/cards/%s", c.baseURL, cardID) + req, err := http.NewRequestWithContext(ctx, "PUT", reqURL, strings.NewReader(data.Encode())) + if err != nil { + return fmt.Errorf("failed to create request: %w", err) + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + // Execute request + resp, err := c.httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to update card: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("trello API error (status %d): %s", resp.StatusCode, string(body)) + } + + return nil } |
