| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269 |
- package plane_v2
- import (
- "encoding/json"
- "fmt"
- )
- // PlaneService 通用 Plane API 封装(无绑定配置,workspace/project 通过参数传入)
- type PlaneService struct {
- Client *PlaneClient
- }
- // NewPlaneService 创建通用 PlaneService(须先调用 InitPlaneClient)
- func NewPlaneService() *PlaneService {
- if globalClient == nil {
- panic("[PlaneService] PlaneClient 未初始化,请先调用 InitPlaneClient")
- }
- return &PlaneService{Client: globalClient}
- }
- // ============ Workspace 方法 ============
- func (s *PlaneService) ListWorkspaces() ([]byte, error) {
- resp, err := s.Client.Get("/api/users/me/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(workspaceSlug string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%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(workspaceSlug string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%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(workspaceSlug string) error {
- url := fmt.Sprintf("/api/workspaces/%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(workspaceSlug string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/", 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(workspaceSlug, projectID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%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(workspaceSlug string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/", 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(workspaceSlug, projectID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%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(workspaceSlug, projectID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%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(workspaceSlug, projectID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/archive/", 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(workspaceSlug, projectID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/archive/", 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(workspaceSlug, projectId string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/", workspaceSlug, 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(workspaceSlug, projectId string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/", workspaceSlug, 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(workspaceSlug, projectId, issueID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/sub-issues/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/archive/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/archive/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/history/?activity_type=issue-property", workspaceSlug, 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
- }
- // ============ Intake 方法 ============
- func (s *PlaneService) CreateIntakeIssue(workspaceSlug, projectId string, issue IntakeIssueRequest) (*IntakeIssueResponse, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/", workspaceSlug, projectId)
- payload := map[string]any{"source": "IN_APP", "issue": issue}
- resp, err := s.Client.Post(url, payload)
- if err != nil {
- return nil, err
- }
- if !IsSuccess(resp.StatusCode) {
- return nil, fmt.Errorf("CreateIntakeIssue 失败: %s", resp.Status)
- }
- var result IntakeIssueResponse
- if err := json.Unmarshal(resp.Body, &result); err != nil {
- return nil, err
- }
- return &result, nil
- }
- func (s *PlaneService) ListIntakeIssues(workspaceSlug, projectId, status string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/", workspaceSlug, projectId)
- if status != "" {
- url += "?status=" + status
- }
- resp, err := s.Client.Get(url)
- if err != nil {
- return nil, err
- }
- if !IsSuccess(resp.StatusCode) {
- return nil, fmt.Errorf("ListIntakeIssues 失败: %s", resp.Status)
- }
- return resp.Body, nil
- }
- func (s *PlaneService) GetIntakeIssue(workspaceSlug, projectId, issueID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/%s/?expand=issue_inbox", workspaceSlug, projectId, issueID)
- resp, err := s.Client.Get(url)
- if err != nil {
- return nil, err
- }
- if !IsSuccess(resp.StatusCode) {
- return nil, fmt.Errorf("GetIntakeIssue 失败: %s", resp.Status)
- }
- return resp.Body, nil
- }
- func (s *PlaneService) UpdateIntakeIssue(workspaceSlug, projectId, issueID string, data map[string]any) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/%s/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) ([]byte, error) {
- return s.UpdateIntakeIssue(workspaceSlug, projectId, issueID, map[string]any{"status": 1})
- }
- func (s *PlaneService) RejectIntakeIssue(workspaceSlug, projectId, issueID string) ([]byte, error) {
- return s.UpdateIntakeIssue(workspaceSlug, projectId, issueID, map[string]any{"status": -1})
- }
- func (s *PlaneService) DeleteIntakeIssue(workspaceSlug, projectId, issueID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/%s/", workspaceSlug, 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) UploadProjectAsset(workspaceSlug, projectId, fileName, mimeType string, fileData []byte, entityType string) (*AssetUploadResult, error) {
- // Step 1: 创建资源
- createURL := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/", workspaceSlug, projectId)
- createPayload := map[string]any{
- "name": fileName, "type": mimeType, "size": len(fileData),
- "entity_type": entityType, "entity_identifier": "",
- }
- resp, err := s.Client.Post(createURL, createPayload)
- 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, err
- }
- // Step 2: 上传到 S3
- if err := s.Client.PostS3(result.UploadData.URL, result.UploadData.Fields, fileData, fileName); err != nil {
- return nil, err
- }
- // Step 3: 确认
- confirmURL := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/%s/", workspaceSlug, projectId, result.AssetID)
- s.Client.Patch(confirmURL, map[string]any{})
- return &result, nil
- }
- func (s *PlaneService) CreateProjectAsset(workspaceSlug, projectId, fileName, mimeType string, size int64, entityType string) (*AssetUploadResult, error) {
- url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/", workspaceSlug, 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(workspaceSlug, projectId, assetID string) error {
- url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/%s/", workspaceSlug, 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) GetProjectAssetURL(workspaceSlug, projectId, assetID string) (string, error) {
- url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/%s/", workspaceSlug, projectId, assetID)
- return s.Client.GetRedirectLocation(url)
- }
- func (s *PlaneService) GetProjectAsset(workspaceSlug, projectId, assetID string) ([]byte, error) {
- url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/%s/", workspaceSlug, projectId, assetID)
- resp, err := s.Client.Get(url)
- if err != nil {
- return nil, err
- }
- return resp.Body, nil
- }
- func (s *PlaneService) DeleteProjectAsset(workspaceSlug, projectId, assetID string) error {
- url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/%s/", workspaceSlug, projectId, assetID)
- resp, err := s.Client.Delete(url)
- if err != nil {
- return err
- }
- if resp.StatusCode != 204 {
- return fmt.Errorf("DeleteProjectAsset 失败: %s", resp.Status)
- }
- return nil
- }
- func (s *PlaneService) BindAssetsToEntity(workspaceSlug, projectId, entityID string, assetIDs []string) error {
- url := fmt.Sprintf("/api/assets/v2/workspaces/%s/projects/%s/%s/bulk/", workspaceSlug, projectId, entityID)
- resp, err := s.Client.Post(url, map[string]any{"asset_ids": assetIDs})
- if err != nil {
- return err
- }
- if resp.StatusCode != 204 && !IsSuccess(resp.StatusCode) {
- return fmt.Errorf("BindAssetsToEntity 失败: %s", resp.Status)
- }
- return nil
- }
- // ============ Cycle 方法 ============
- func (s *PlaneService) ListCycles(workspaceSlug, projectId string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/", workspaceSlug, 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(workspaceSlug, projectId, cycleID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/", workspaceSlug, 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(workspaceSlug, projectId string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/", workspaceSlug, 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(workspaceSlug, projectId, cycleID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/", workspaceSlug, 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(workspaceSlug, projectId, cycleID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/", workspaceSlug, 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(workspaceSlug, projectId, cycleID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/cycle-issues/", workspaceSlug, 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(workspaceSlug, projectId, cycleID string, issueIDs []string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/cycle-issues/", workspaceSlug, 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(workspaceSlug, projectId, cycleID, issueID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/cycle-issues/%s/", workspaceSlug, 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(workspaceSlug, projectId, cycleID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/archive/", workspaceSlug, 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(workspaceSlug, projectId, cycleID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/cycles/%s/archive/", workspaceSlug, 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(workspaceSlug, projectId string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/", workspaceSlug, 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(workspaceSlug, projectId, moduleID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/", workspaceSlug, 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(workspaceSlug, projectId string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/", workspaceSlug, 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(workspaceSlug, projectId, moduleID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/", workspaceSlug, 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(workspaceSlug, projectId, moduleID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/", workspaceSlug, 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(workspaceSlug, projectId, moduleID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/module-issues/", workspaceSlug, 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(workspaceSlug, projectId, moduleID string, issueIDs []string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/module-issues/", workspaceSlug, 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(workspaceSlug, projectId, moduleID, issueID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/module-issues/%s/", workspaceSlug, 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(workspaceSlug, projectId, moduleID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/archive/", workspaceSlug, 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(workspaceSlug, projectId, moduleID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/modules/%s/archive/", workspaceSlug, 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(workspaceSlug, projectId string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issue-labels/", workspaceSlug, 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(workspaceSlug, projectId, labelID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issue-labels/%s/", workspaceSlug, 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(workspaceSlug, projectId, name, color string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issue-labels/", workspaceSlug, 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(workspaceSlug, projectId, labelID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issue-labels/%s/", workspaceSlug, 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(workspaceSlug, projectId, labelID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issue-labels/%s/", workspaceSlug, 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(workspaceSlug, projectId string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/", workspaceSlug, 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(workspaceSlug, projectId, stateID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/%s/", workspaceSlug, 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(workspaceSlug, projectId, name, color, group string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/", workspaceSlug, 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(workspaceSlug, projectId, stateID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/%s/", workspaceSlug, 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(workspaceSlug, projectId, stateID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/%s/", workspaceSlug, 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(workspaceSlug, projectId, stateID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/states/%s/default/", workspaceSlug, 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
- }
- // ============ Page 方法 ============
- func (s *PlaneService) ListPages(workspaceSlug, projectId string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/", workspaceSlug, projectId)
- resp, err := s.Client.Get(url)
- if err != nil {
- return nil, err
- }
- if !IsSuccess(resp.StatusCode) {
- return nil, fmt.Errorf("ListPages 失败: %s", resp.Status)
- }
- return resp.Body, nil
- }
- func (s *PlaneService) GetPage(workspaceSlug, projectId, pageID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/", workspaceSlug, projectId, pageID)
- resp, err := s.Client.Get(url)
- if err != nil {
- return nil, err
- }
- if !IsSuccess(resp.StatusCode) {
- return nil, fmt.Errorf("GetPage 失败: %s", resp.Status)
- }
- return resp.Body, nil
- }
- func (s *PlaneService) GetPageDescription(workspaceSlug, projectId, pageID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/description/", workspaceSlug, projectId, pageID)
- resp, err := s.Client.Get(url)
- if err != nil {
- return nil, err
- }
- if !IsSuccess(resp.StatusCode) {
- return nil, fmt.Errorf("GetPageDescription 失败: %s", resp.Status)
- }
- return resp.Body, nil
- }
- func (s *PlaneService) CreatePage(workspaceSlug, projectId string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/", workspaceSlug, 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(workspaceSlug, projectId, pageID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/", workspaceSlug, 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(workspaceSlug, projectId, pageID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/", workspaceSlug, 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(workspaceSlug, projectId, pageID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/archive/", workspaceSlug, 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(workspaceSlug, projectId, pageID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/pages/%s/archive/", workspaceSlug, 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
- }
- // ============ Comment 方法 ============
- func (s *PlaneService) ListComments(workspaceSlug, projectId, issueID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/", workspaceSlug, 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(workspaceSlug, projectId, issueID, commentID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/%s/", workspaceSlug, 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(workspaceSlug, projectId, issueID, commentHTML string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/", workspaceSlug, 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(workspaceSlug, projectId, issueID, commentID, commentHTML string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/%s/", workspaceSlug, 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(workspaceSlug, projectId, issueID, commentID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/comments/%s/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/links/", workspaceSlug, 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(workspaceSlug, projectId, issueID, linkURL, title string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/links/", workspaceSlug, 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(workspaceSlug, projectId, issueID, linkID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/links/%s/", workspaceSlug, 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(workspaceSlug, projectId, issueID, linkID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/links/%s/", workspaceSlug, 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(workspaceSlug, projectId, issueID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/relations/", workspaceSlug, 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(workspaceSlug, projectId, issueID, relationType string, relatedIDs []string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/relations/", workspaceSlug, 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(workspaceSlug, projectId, issueID, relationType, relatedID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/issues/%s/relations/%s/%s/", workspaceSlug, 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
- }
- // ============ Member 方法 ============
- func (s *PlaneService) ListWorkspaceMembers(workspaceSlug string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/members/", 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(workspaceSlug, memberID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/members/%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(workspaceSlug, memberID string, role int) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/members/%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(workspaceSlug, memberID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/members/%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(workspaceSlug, projectId string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/", workspaceSlug, 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(workspaceSlug, projectId, memberID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/%s/", workspaceSlug, 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(workspaceSlug, projectId, memberID string, role int) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/", workspaceSlug, 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(workspaceSlug, projectId, memberID string, role int) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/%s/", workspaceSlug, 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(workspaceSlug, projectId, memberID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/members/%s/", workspaceSlug, 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
- }
- // ============ Sticky 方法 ============
- func (s *PlaneService) ListStickies(workspaceSlug string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/stickies/", 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(workspaceSlug, stickyID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/stickies/%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(workspaceSlug string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/stickies/", 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(workspaceSlug, stickyID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/stickies/%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(workspaceSlug, stickyID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/stickies/%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
- }
|