package labels import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/url" "github.com/frenocorp/pop/internal/api" ) type Client struct { apiClient *api.ProtonMailClient baseURL string } func NewClient(apiClient *api.ProtonMailClient) *Client { return &Client{ apiClient: apiClient, baseURL: apiClient.GetBaseURL(), } } // --- Folders --- func (c *Client) ListFolders() (*ListFoldersResponse, error) { reqURL := fmt.Sprintf("%s/api/folders", c.baseURL) httpReq, err := http.NewRequest("GET", reqURL, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Accept", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return nil, fmt.Errorf("failed to list folders: %w", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } var result ListFoldersResponse if err := json.Unmarshal(respBody, &result); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } return &result, nil } func (c *Client) GetFolder(folderID string) (*Folder, error) { reqURL := fmt.Sprintf("%s/api/folders/%s", c.baseURL, url.QueryEscape(folderID)) httpReq, err := http.NewRequest("GET", reqURL, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Accept", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return nil, fmt.Errorf("failed to get folder: %w", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } var result struct { Data Folder `json:"Data"` } if err := json.Unmarshal(respBody, &result); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } return &result.Data, nil } func (c *Client) CreateFolder(req CreateFolderRequest) (*Folder, error) { if req.Name == "" { return nil, fmt.Errorf("folder name is required") } body, err := json.Marshal(req) if err != nil { return nil, fmt.Errorf("failed to marshal request: %w", err) } reqURL := fmt.Sprintf("%s/api/folders", c.baseURL) httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(body)) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Content-Type", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return nil, fmt.Errorf("failed to create folder: %w", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } var result struct { Data Folder `json:"Data"` } if err := json.Unmarshal(respBody, &result); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } return &result.Data, nil } func (c *Client) UpdateFolder(folderID string, req UpdateFolderRequest) (*Folder, error) { body, err := json.Marshal(req) if err != nil { return nil, fmt.Errorf("failed to marshal request: %w", err) } reqURL := fmt.Sprintf("%s/api/folders/%s", c.baseURL, url.QueryEscape(folderID)) httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(body)) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Content-Type", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return nil, fmt.Errorf("failed to update folder: %w", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } var result struct { Data Folder `json:"Data"` } if err := json.Unmarshal(respBody, &result); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } return &result.Data, nil } func (c *Client) DeleteFolder(folderID string) error { reqURL := fmt.Sprintf("%s/api/folders/%s", c.baseURL, url.QueryEscape(folderID)) httpReq, err := http.NewRequest("POST", reqURL, nil) if err != nil { return fmt.Errorf("failed to create request: %w", err) } resp, err := c.apiClient.Do(httpReq) if err != nil { return fmt.Errorf("failed to delete folder: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("delete failed (status %d): %s", resp.StatusCode, string(body)) } return nil } // --- Labels --- func (c *Client) ListLabels() (*ListLabelsResponse, error) { reqURL := fmt.Sprintf("%s/api/labels", c.baseURL) httpReq, err := http.NewRequest("GET", reqURL, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Accept", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return nil, fmt.Errorf("failed to list labels: %w", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } var result ListLabelsResponse if err := json.Unmarshal(respBody, &result); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } return &result, nil } func (c *Client) CreateLabel(req CreateLabelRequest) (*Label, error) { if req.Name == "" { return nil, fmt.Errorf("label name is required") } body, err := json.Marshal(req) if err != nil { return nil, fmt.Errorf("failed to marshal request: %w", err) } reqURL := fmt.Sprintf("%s/api/labels", c.baseURL) httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(body)) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Content-Type", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return nil, fmt.Errorf("failed to create label: %w", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } var result struct { Data Label `json:"Data"` } if err := json.Unmarshal(respBody, &result); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } return &result.Data, nil } func (c *Client) UpdateLabel(labelID string, req UpdateLabelRequest) (*Label, error) { body, err := json.Marshal(req) if err != nil { return nil, fmt.Errorf("failed to marshal request: %w", err) } reqURL := fmt.Sprintf("%s/api/labels/%s", c.baseURL, url.QueryEscape(labelID)) httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(body)) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Content-Type", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return nil, fmt.Errorf("failed to update label: %w", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } var result struct { Data Label `json:"Data"` } if err := json.Unmarshal(respBody, &result); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } return &result.Data, nil } func (c *Client) DeleteLabel(labelID string) error { reqURL := fmt.Sprintf("%s/api/labels/%s", c.baseURL, url.QueryEscape(labelID)) httpReq, err := http.NewRequest("POST", reqURL, nil) if err != nil { return fmt.Errorf("failed to create request: %w", err) } resp, err := c.apiClient.Do(httpReq) if err != nil { return fmt.Errorf("failed to delete label: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("delete failed (status %d): %s", resp.StatusCode, string(body)) } return nil } // --- Message Labels --- func (c *Client) ApplyLabel(messageID, labelID string) error { if messageID == "" || labelID == "" { return fmt.Errorf("message ID and label ID are required") } body := map[string]string{ "LabelID": labelID, } jsonBody, err := json.Marshal(body) if err != nil { return fmt.Errorf("failed to marshal request: %w", err) } reqURL := fmt.Sprintf("%s/api/messages/%s/setlabel", c.baseURL, url.QueryEscape(messageID)) httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody)) if err != nil { return fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Content-Type", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return fmt.Errorf("failed to apply label: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("apply label failed (status %d): %s", resp.StatusCode, string(body)) } return nil } func (c *Client) RemoveLabel(messageID, labelID string) error { if messageID == "" || labelID == "" { return fmt.Errorf("message ID and label ID are required") } body := map[string]string{ "LabelID": labelID, } jsonBody, err := json.Marshal(body) if err != nil { return fmt.Errorf("failed to marshal request: %w", err) } reqURL := fmt.Sprintf("%s/api/messages/%s/clearlabel", c.baseURL, url.QueryEscape(messageID)) httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody)) if err != nil { return fmt.Errorf("failed to create request: %w", err) } httpReq.Header.Set("Content-Type", "application/json") resp, err := c.apiClient.Do(httpReq) if err != nil { return fmt.Errorf("failed to remove label: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("remove label failed (status %d): %s", resp.StatusCode, string(body)) } return nil }