package tui import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "net/url" "time" "git.unkin.net/unkin/forgebot/pkg/models" ) type Client struct { baseURL string httpClient *http.Client } func NewClient(baseURL string) *Client { return &Client{ baseURL: baseURL, httpClient: &http.Client{Timeout: 10 * time.Second}, } } func (c *Client) ListTasks(ctx context.Context, status, repository string) ([]models.Task, error) { u := c.baseURL + "/api/v1/tasks" params := url.Values{} if status != "" { params.Set("status", status) } if repository != "" { params.Set("repository", repository) } if len(params) > 0 { u += "?" + params.Encode() } req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { return nil, err } resp, err := c.httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("GET %s: %d %s", u, resp.StatusCode, string(body)) } var tasks []models.Task if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil { return nil, err } return tasks, nil } func (c *Client) GetTask(ctx context.Context, id string) (*models.Task, error) { u := c.baseURL + "/api/v1/tasks/" + id req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { return nil, err } resp, err := c.httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("GET %s: %d %s", u, resp.StatusCode, string(body)) } var task models.Task if err := json.NewDecoder(resp.Body).Decode(&task); err != nil { return nil, err } return &task, nil } func (c *Client) CreateTask(ctx context.Context, req models.CreateTaskRequest) (*models.Task, error) { body, err := json.Marshal(req) if err != nil { return nil, err } u := c.baseURL + "/api/v1/tasks" httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, u, bytes.NewReader(body)) if err != nil { return nil, err } httpReq.Header.Set("Content-Type", "application/json") resp, err := c.httpClient.Do(httpReq) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusCreated { respBody, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("POST %s: %d %s", u, resp.StatusCode, string(respBody)) } var task models.Task if err := json.NewDecoder(resp.Body).Decode(&task); err != nil { return nil, err } return &task, nil } func (c *Client) UpdateTask(ctx context.Context, id string, req models.UpdateTaskRequest) error { body, err := json.Marshal(req) if err != nil { return err } u := c.baseURL + "/api/v1/tasks/" + id httpReq, err := http.NewRequestWithContext(ctx, http.MethodPatch, u, bytes.NewReader(body)) if err != nil { return err } httpReq.Header.Set("Content-Type", "application/json") resp, err := c.httpClient.Do(httpReq) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusNoContent { respBody, _ := io.ReadAll(resp.Body) return fmt.Errorf("PATCH %s: %d %s", u, resp.StatusCode, string(respBody)) } return nil }