Released v1

This commit is contained in:
Steve Cliff
2026-02-12 10:37:19 +00:00
commit b07572fed5
77 changed files with 19518 additions and 0 deletions
+250
View File
@@ -0,0 +1,250 @@
package client
import (
"context"
"encoding/json"
"fmt"
"log/slog"
"git.franklin.lab/steve.cliff/pcli/model"
)
func (c *Client) GetCard(ctx context.Context, id string) (*model.Card, error) {
data, err := c.DoNoBody(ctx, "GET", fmt.Sprintf("/api/cards/%s", id))
if err != nil {
return nil, err
}
var response struct {
Item model.Card `json:"item"`
}
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal card response: %w", err)
}
return &response.Item, nil
}
func (c *Client) CreateCard(ctx context.Context, listId string, fields map[string]any) (*model.Card, error) {
data, err := c.Do(ctx, "POST", fmt.Sprintf("/api/lists/%s/cards", listId), fields)
if err != nil {
return nil, err
}
var response struct {
Item model.Card `json:"item"`
}
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal card response: %w", err)
}
return &response.Item, nil
}
func (c *Client) UpdateCard(ctx context.Context, id string, fields map[string]any) (*model.Card, error) {
data, err := c.Do(ctx, "PATCH", fmt.Sprintf("/api/cards/%s", id), fields)
if err != nil {
return nil, err
}
var response struct {
Item model.Card `json:"item"`
}
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal card response: %w", err)
}
return &response.Item, nil
}
func (c *Client) DeleteCard(ctx context.Context, id string) error {
_, err := c.DoNoBody(ctx, "DELETE", fmt.Sprintf("/api/cards/%s", id))
return err
}
func (c *Client) DuplicateCard(ctx context.Context, id string, name *string, position *float64) (*model.Card, error) {
fields := make(map[string]any)
if name != nil {
fields["name"] = *name
}
if position != nil {
fields["position"] = *position
}
data, err := c.Do(ctx, "POST", fmt.Sprintf("/api/cards/%s/duplicate", id), fields)
if err != nil {
return nil, err
}
var response struct {
Item model.Card `json:"item"`
}
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal card response: %w", err)
}
return &response.Item, nil
}
func (c *Client) ListCards(ctx context.Context, listId string, limit int) ([]model.Card, error) {
var all []model.Card
var before string
for {
path := fmt.Sprintf("/api/lists/%s/cards", listId)
if before != "" {
path = fmt.Sprintf("%s?before=%s", path, before)
}
c.Logger.Debug("Fetching cards page",
slog.String("listId", listId),
slog.String("before", before),
)
data, err := c.DoNoBody(ctx, "GET", path)
if err != nil {
return nil, err
}
var response struct {
Items []model.Card `json:"items"`
}
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal cards response: %w", err)
}
if len(response.Items) == 0 {
break
}
all = append(all, response.Items...)
if limit > 0 && len(all) >= limit {
all = all[:limit]
break
}
before = response.Items[len(response.Items)-1].ID
}
return all, nil
}
func (c *Client) ListCardActions(ctx context.Context, cardId string, limit int) ([]model.Action, error) {
var all []model.Action
var beforeId string
for {
path := fmt.Sprintf("/api/cards/%s/actions", cardId)
if beforeId != "" {
path = fmt.Sprintf("%s?beforeId=%s", path, beforeId)
}
c.Logger.Debug("Fetching card actions page",
slog.String("cardId", cardId),
slog.String("beforeId", beforeId),
)
data, err := c.DoNoBody(ctx, "GET", path)
if err != nil {
return nil, err
}
var response struct {
Items []model.Action `json:"items"`
}
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal card actions response: %w", err)
}
if len(response.Items) == 0 {
break
}
all = append(all, response.Items...)
if limit > 0 && len(all) >= limit {
all = all[:limit]
break
}
beforeId = response.Items[len(response.Items)-1].ID
}
return all, nil
}
func (c *Client) ListCardsByBoard(ctx context.Context, boardId string, limit int) ([]model.CardWithList, error) {
board, err := c.GetBoard(ctx, boardId)
if err != nil {
return nil, fmt.Errorf("failed to get board: %w", err)
}
listNames := make(map[string]string)
for _, list := range board.Lists {
name := ""
if list.Name != nil {
name = *list.Name
}
listNames[list.ID] = name
}
var allCards []model.CardWithList
for _, card := range board.Cards {
cardWithList := model.CardWithList{
Card: card,
ListName: listNames[card.ListID],
}
allCards = append(allCards, cardWithList)
if limit > 0 && len(allCards) >= limit {
return allCards[:limit], nil
}
}
return allCards, nil
}
func (c *Client) AddCardLabel(ctx context.Context, cardId, labelId string) error {
fields := map[string]any{
"labelId": labelId,
}
_, err := c.DoWithFallback(ctx, "POST",
fmt.Sprintf("/api/cards/%s/card-labels", cardId),
fmt.Sprintf("/api/cards/%s/labels", cardId),
fields)
return err
}
func (c *Client) RemoveCardLabel(ctx context.Context, cardId, labelId string) error {
_, err := c.DoNoBodyWithFallback(ctx, "DELETE",
fmt.Sprintf("/api/cards/%s/card-labels/labelId:%s", cardId, labelId),
fmt.Sprintf("/api/cards/%s/labels/%s", cardId, labelId))
return err
}
func (c *Client) AddCardMember(ctx context.Context, cardId, userId string) error {
fields := map[string]any{
"userId": userId,
}
_, err := c.DoWithFallback(ctx, "POST",
fmt.Sprintf("/api/cards/%s/card-memberships", cardId),
fmt.Sprintf("/api/cards/%s/memberships", cardId),
fields)
return err
}
func (c *Client) RemoveCardMember(ctx context.Context, cardId, userId string) error {
_, err := c.DoNoBodyWithFallback(ctx, "DELETE",
fmt.Sprintf("/api/cards/%s/card-memberships/userId:%s", cardId, userId),
fmt.Sprintf("/api/cards/%s/memberships/%s", cardId, userId))
return err
}