|
@@ -3,7 +3,6 @@ package plane_v2
|
|
|
import (
|
|
import (
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
- "fwh-toolbox-server/config"
|
|
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
// PlaneService 便捷封装(绑定固定的 workspace/project,共享全局 PlaneClient)
|
|
// PlaneService 便捷封装(绑定固定的 workspace/project,共享全局 PlaneClient)
|
|
@@ -17,18 +16,18 @@ type PlaneService struct {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// NewPlaneService 创建 PlaneService(须先调用 InitPlaneClient)
|
|
// NewPlaneService 创建 PlaneService(须先调用 InitPlaneClient)
|
|
|
-func NewPlaneService(cfg *config.PlaneWebApiConfig) *PlaneService {
|
|
|
|
|
|
|
+func NewPlaneService(workspaceSlug, projectId, labelBugId, labelFeatureId, labelFeedbackId string) *PlaneService {
|
|
|
if globalClient == nil {
|
|
if globalClient == nil {
|
|
|
panic("[PlaneService] PlaneClient 未初始化,请先调用 InitPlaneClient")
|
|
panic("[PlaneService] PlaneClient 未初始化,请先调用 InitPlaneClient")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return &PlaneService{
|
|
return &PlaneService{
|
|
|
Client: globalClient,
|
|
Client: globalClient,
|
|
|
- WorkspaceSlug: cfg.WorkspaceSlug,
|
|
|
|
|
- ProjectId: cfg.ProjectId,
|
|
|
|
|
- LabelBugId: cfg.LabelBugId,
|
|
|
|
|
- LabelFeatureId: cfg.LabelFeatureId,
|
|
|
|
|
- LabelFeedbackId: cfg.LabelFeedbackId,
|
|
|
|
|
|
|
+ WorkspaceSlug: workspaceSlug,
|
|
|
|
|
+ ProjectId: projectId,
|
|
|
|
|
+ LabelBugId: labelBugId,
|
|
|
|
|
+ LabelFeatureId: labelFeatureId,
|
|
|
|
|
+ LabelFeedbackId: labelFeedbackId,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -178,3 +177,1112 @@ func (s *PlaneService) GetPageDescription(pageID string) ([]byte, error) {
|
|
|
}
|
|
}
|
|
|
return resp.Body, nil
|
|
return resp.Body, nil
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Workspace 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListWorkspaces() ([]byte, error) {
|
|
|
|
|
+ resp, err := s.Client.Get("/api/workspaces/")
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListWorkspaces 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetWorkspace() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/", s.WorkspaceSlug)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetWorkspace 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateWorkspace(name, slug string) ([]byte, error) {
|
|
|
|
|
+ payload := map[string]interface{}{"name": name, "slug": slug}
|
|
|
|
|
+ resp, err := s.Client.Post("/api/workspaces/", payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateWorkspace 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateWorkspace(data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/", s.WorkspaceSlug)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateWorkspace 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteWorkspace() error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/", s.WorkspaceSlug)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteWorkspace 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Project 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListProjects() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/", s.WorkspaceSlug)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListProjects 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetProject(projectID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/", s.WorkspaceSlug, projectID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetProject 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateProject(data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/", s.WorkspaceSlug)
|
|
|
|
|
+ resp, err := s.Client.Post(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateProject 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateProject(projectID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/", s.WorkspaceSlug, projectID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateProject 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteProject(projectID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/", s.WorkspaceSlug, projectID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteProject 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ArchiveProject(projectID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/archive/", s.WorkspaceSlug, projectID)
|
|
|
|
|
+ resp, err := s.Client.Post(url, nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("ArchiveProject 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UnarchiveProject(projectID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/archive/", s.WorkspaceSlug, projectID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("UnarchiveProject 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Issue 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListIssues() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListIssues 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetIssue(issueID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetIssue 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateIssue(data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Post(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateIssue 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateIssue(issueID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateIssue 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteIssue(issueID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteIssue 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetSubIssues(issueID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/sub-issues/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetSubIssues 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ArchiveIssue(issueID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/archive/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Post(url, nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("ArchiveIssue 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UnarchiveIssue(issueID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/archive/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("UnarchiveIssue 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetIssueActivity(issueID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/history/?activity_type=issue-property", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetIssueActivity 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Cycle 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListCycles() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListCycles 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetCycle(cycleID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/", s.WorkspaceSlug, s.ProjectId, cycleID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetCycle 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateCycle(data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Post(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateCycle 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateCycle(cycleID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/", s.WorkspaceSlug, s.ProjectId, cycleID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateCycle 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteCycle(cycleID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/", s.WorkspaceSlug, s.ProjectId, cycleID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteCycle 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListCycleIssues(cycleID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/cycle-issues/", s.WorkspaceSlug, s.ProjectId, cycleID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListCycleIssues 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) AddIssuesToCycle(cycleID string, issueIDs []string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/cycle-issues/", s.WorkspaceSlug, s.ProjectId, cycleID)
|
|
|
|
|
+ payload := map[string]interface{}{"issues": issueIDs}
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("AddIssuesToCycle 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) RemoveIssueFromCycle(cycleID, issueID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/cycle-issues/%s/", s.WorkspaceSlug, s.ProjectId, cycleID, issueID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("RemoveIssueFromCycle 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ArchiveCycle(cycleID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/archive/", s.WorkspaceSlug, s.ProjectId, cycleID)
|
|
|
|
|
+ resp, err := s.Client.Post(url, nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("ArchiveCycle 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UnarchiveCycle(cycleID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/archive/", s.WorkspaceSlug, s.ProjectId, cycleID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("UnarchiveCycle 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Module 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListModules() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListModules 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetModule(moduleID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/", s.WorkspaceSlug, s.ProjectId, moduleID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetModule 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateModule(data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Post(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateModule 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateModule(moduleID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/", s.WorkspaceSlug, s.ProjectId, moduleID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateModule 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteModule(moduleID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/", s.WorkspaceSlug, s.ProjectId, moduleID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteModule 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListModuleIssues(moduleID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/module-issues/", s.WorkspaceSlug, s.ProjectId, moduleID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListModuleIssues 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) AddIssuesToModule(moduleID string, issueIDs []string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/module-issues/", s.WorkspaceSlug, s.ProjectId, moduleID)
|
|
|
|
|
+ payload := map[string]interface{}{"issues": issueIDs}
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("AddIssuesToModule 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) RemoveIssueFromModule(moduleID, issueID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/module-issues/%s/", s.WorkspaceSlug, s.ProjectId, moduleID, issueID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("RemoveIssueFromModule 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ArchiveModule(moduleID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/archive/", s.WorkspaceSlug, s.ProjectId, moduleID)
|
|
|
|
|
+ resp, err := s.Client.Post(url, nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("ArchiveModule 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UnarchiveModule(moduleID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/archive/", s.WorkspaceSlug, s.ProjectId, moduleID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("UnarchiveModule 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Label 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListLabels() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/labels/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListLabels 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetLabel(labelID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/labels/%s/", s.WorkspaceSlug, s.ProjectId, labelID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetLabel 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateLabel(name, color string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/labels/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ payload := map[string]interface{}{"name": name, "color": color}
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateLabel 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateLabel(labelID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/labels/%s/", s.WorkspaceSlug, s.ProjectId, labelID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateLabel 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteLabel(labelID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/labels/%s/", s.WorkspaceSlug, s.ProjectId, labelID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteLabel 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ State 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListStates() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListStates 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetState(stateID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/%s/", s.WorkspaceSlug, s.ProjectId, stateID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetState 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateState(name, color, group string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ payload := map[string]interface{}{"name": name, "color": color, "group": group}
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateState 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateState(stateID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/%s/", s.WorkspaceSlug, s.ProjectId, stateID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateState 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteState(stateID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/%s/", s.WorkspaceSlug, s.ProjectId, stateID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteState 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) MarkStateDefault(stateID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/%s/default/", s.WorkspaceSlug, s.ProjectId, stateID)
|
|
|
|
|
+ resp, err := s.Client.Post(url, nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("MarkStateDefault 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Comment 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListComments(issueID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListComments 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetComment(issueID, commentID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/%s/", s.WorkspaceSlug, s.ProjectId, issueID, commentID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetComment 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateComment(issueID, commentHTML string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ payload := map[string]interface{}{"comment_html": commentHTML}
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateComment 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateComment(issueID, commentID, commentHTML string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/%s/", s.WorkspaceSlug, s.ProjectId, issueID, commentID)
|
|
|
|
|
+ payload := map[string]interface{}{"comment_html": commentHTML}
|
|
|
|
|
+ resp, err := s.Client.Patch(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateComment 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteComment(issueID, commentID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/%s/", s.WorkspaceSlug, s.ProjectId, issueID, commentID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteComment 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Link 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListIssueLinks(issueID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/links/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListIssueLinks 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateIssueLink(issueID, linkURL, title string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/links/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ payload := map[string]interface{}{"url": linkURL, "title": title}
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateIssueLink 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateIssueLink(issueID, linkID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/links/%s/", s.WorkspaceSlug, s.ProjectId, issueID, linkID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateIssueLink 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteIssueLink(issueID, linkID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/links/%s/", s.WorkspaceSlug, s.ProjectId, issueID, linkID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteIssueLink 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Relation 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListIssueRelations(issueID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/relations/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListIssueRelations 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateIssueRelation(issueID, relationType string, relatedIDs []string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/relations/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ payload := map[string]interface{}{"relation_type": relationType, "related_issues": relatedIDs}
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateIssueRelation 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) RemoveIssueRelation(issueID, relationType, relatedID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/relations/%s/%s/", s.WorkspaceSlug, s.ProjectId, issueID, relationType, relatedID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("RemoveIssueRelation 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Sticky 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListStickies() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/stickies/", s.WorkspaceSlug)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListStickies 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetSticky(stickyID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/stickies/%s/", s.WorkspaceSlug, stickyID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetSticky 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateSticky(data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/stickies/", s.WorkspaceSlug)
|
|
|
|
|
+ resp, err := s.Client.Post(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateSticky 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateSticky(stickyID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/stickies/%s/", s.WorkspaceSlug, stickyID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateSticky 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteSticky(stickyID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/stickies/%s/", s.WorkspaceSlug, stickyID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteSticky 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Intake 补充方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateIntakeIssue(issueID string, data map[string]any) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/%s/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateIntakeIssue 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) AcceptIntakeIssue(issueID string) ([]byte, error) {
|
|
|
|
|
+ return s.UpdateIntakeIssue(issueID, map[string]any{"status": 1})
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) RejectIntakeIssue(issueID string) ([]byte, error) {
|
|
|
|
|
+ return s.UpdateIntakeIssue(issueID, map[string]any{"status": -1})
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeleteIntakeIssue(issueID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/%s/", s.WorkspaceSlug, s.ProjectId, issueID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeleteIntakeIssue 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Asset 补充方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreateProjectAsset(fileName, mimeType string, size int64, entityType string) (*AssetUploadResult, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ payload := map[string]interface{}{
|
|
|
|
|
+ "name": fileName, "type": mimeType, "size": size,
|
|
|
|
|
+ "entity_type": entityType, "entity_identifier": "",
|
|
|
|
|
+ }
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreateProjectAsset 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ var result AssetUploadResult
|
|
|
|
|
+ if err := json.Unmarshal(resp.Body, &result); err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("解析响应失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return &result, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ConfirmProjectAssetUpload(assetID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/%s/", s.WorkspaceSlug, s.ProjectId, assetID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, map[string]interface{}{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 && !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("ConfirmProjectAssetUpload 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetProjectAsset(assetID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/%s/", s.WorkspaceSlug, s.ProjectId, assetID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Page 补充方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) CreatePage(data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Post(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("CreatePage 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdatePage(pageID string, data map[string]interface{}) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/", s.WorkspaceSlug, s.ProjectId, pageID)
|
|
|
|
|
+ resp, err := s.Client.Patch(url, data)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdatePage 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) DeletePage(pageID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/", s.WorkspaceSlug, s.ProjectId, pageID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("DeletePage 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ArchivePage(pageID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/archive/", s.WorkspaceSlug, s.ProjectId, pageID)
|
|
|
|
|
+ resp, err := s.Client.Post(url, nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("ArchivePage 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UnarchivePage(pageID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/archive/", s.WorkspaceSlug, s.ProjectId, pageID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return fmt.Errorf("UnarchivePage 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ============ Member 便捷方法 ============
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListWorkspaceMembers() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/members/", s.WorkspaceSlug)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListWorkspaceMembers 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetWorkspaceMember(memberID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/members/%s/", s.WorkspaceSlug, memberID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetWorkspaceMember 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateWorkspaceMemberRole(memberID string, role int) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/members/%s/", s.WorkspaceSlug, memberID)
|
|
|
|
|
+ payload := map[string]interface{}{"role": role}
|
|
|
|
|
+ resp, err := s.Client.Patch(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateWorkspaceMemberRole 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) RemoveWorkspaceMember(memberID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/members/%s/", s.WorkspaceSlug, memberID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("RemoveWorkspaceMember 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) ListProjectMembers() ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("ListProjectMembers 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) GetProjectMember(memberID string) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/%s/", s.WorkspaceSlug, s.ProjectId, memberID)
|
|
|
|
|
+ resp, err := s.Client.Get(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("GetProjectMember 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) AddProjectMember(memberID string, role int) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/", s.WorkspaceSlug, s.ProjectId)
|
|
|
|
|
+ payload := map[string]interface{}{"member": memberID, "role": role}
|
|
|
|
|
+ resp, err := s.Client.Post(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("AddProjectMember 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) UpdateProjectMemberRole(memberID string, role int) ([]byte, error) {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/%s/", s.WorkspaceSlug, s.ProjectId, memberID)
|
|
|
|
|
+ payload := map[string]interface{}{"role": role}
|
|
|
|
|
+ resp, err := s.Client.Patch(url, payload)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !IsSuccess(resp.StatusCode) {
|
|
|
|
|
+ return nil, fmt.Errorf("UpdateProjectMemberRole 失败: %s, body=%s", resp.Status, string(resp.Body))
|
|
|
|
|
+ }
|
|
|
|
|
+ return resp.Body, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *PlaneService) RemoveProjectMember(memberID string) error {
|
|
|
|
|
+ url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/%s/", s.WorkspaceSlug, s.ProjectId, memberID)
|
|
|
|
|
+ resp, err := s.Client.Delete(url)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if resp.StatusCode != 204 {
|
|
|
|
|
+ return fmt.Errorf("RemoveProjectMember 失败: %s", resp.Status)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|