Skip to content

add universe search sdk #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 31, 2025
19 changes: 14 additions & 5 deletions core/apiresp.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ type CodeError struct {
ErrCode int `json:"err_code"`
ErrMsg string `json:"err_msg"`
Err struct {
Code int `json:"code,omitempty"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
Msg string `json:"msg,omitempty"`
LogID string `json:"log_id,omitempty"`
} `json:"err"`
}

Expand All @@ -65,10 +66,18 @@ func (ce CodeError) Error() string {

func (ce CodeError) String() string {
sb := strings.Builder{}
sb.WriteString("msg:")
sb.WriteString(ce.ErrMsg)
sb.WriteString(",code:")
sb.WriteString("resp err, code:")
sb.WriteString(strconv.Itoa(ce.ErrCode))
sb.WriteString(", msg:")
sb.WriteString(ce.ErrMsg)
sb.WriteString(", inner code:")
sb.WriteString(strconv.Itoa(ce.Err.Code))
sb.WriteString(", inner msg:")
sb.WriteString(ce.Err.Msg)
if len(ce.Err.LogID) > 0 {
sb.WriteString(", log_id:")
sb.WriteString(ce.Err.LogID)
}
return sb.String()
}

Expand Down
20 changes: 20 additions & 0 deletions core/apiresp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package core

import "testing"

func TestAPIResp_Error_String(t *testing.T) {
err := CodeError{
ErrCode: 10001,
ErrMsg: "error message",
Err: struct {
Code int `json:"code,omitempty"`
Msg string `json:"msg,omitempty"`
LogID string `json:"log_id,omitempty"`
}{
Code: 10002,
Msg: "inner error message",
LogID: "20210101000001",
},
}
t.Logf(err.String())
}
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/larksuite/project-oapi-sdk-golang

go 1.15
go 1.22.0

toolchain go1.22.2
14 changes: 8 additions & 6 deletions service/field/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,25 @@ type QueryLink struct {
type SimpleField struct {
FieldKey string `json:"field_key"`

FieldTypeKey string `json:"field_type_key"`

Options []*Option `json:"options"`

CompoundFields []*SimpleField `json:"compound_fields"`

FieldAlias string `json:"field_alias"`

FieldTypeKey string `json:"field_type_key"`

FieldName string `json:"field_name"`

IsCustomField bool `json:"is_custom_field"`

Options []*Option `json:"options"`

CompoundFields []*SimpleField `json:"compound_fields"`

IsObsoleted bool `json:"is_obsoleted"`

WorkItemScopes []string `json:"work_item_scopes"`

ValueGenerateMode string `json:"value_generate_mode"`

RelationID string `json:"relation_id"`
}

type TargetState struct {
Expand Down
26 changes: 26 additions & 0 deletions service/workitem/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ const APIPathUpdateWorkingHourRecord = "/open_api/:project_key/work_item/:work_i

const APIPathWbsView = "/open_api/:project_key/work_item/:work_item_type_key/:work_item_id/wbs_view"

const APIPath_UniversalSearch = "/open_api/view_search/universal_search"

func NewService(config *core.Config) *WorkItemService {
a := &WorkItemService{config: config}
return a
Expand Down Expand Up @@ -598,3 +600,27 @@ func (a *WorkItemService) WbsView(ctx context.Context, req *WbsViewReq, options
}
return resp, err
}

/*
* @name: openapi获取指定的工作项列表(极简链路,替代原有的GeneralSearch系列)
* @desc: openapi获取指定的工作项列表(极简链路,替代原有的GeneralSearch系列)
*/
func (a *WorkItemService) UniversalSearch(ctx context.Context, req *UniversalSearchReq, options ...core.RequestOptionFunc) (*UniversalSearchResp, error) {
// 发起请求
apiReq := req.apiReq
apiReq.ApiPath = APIPath_UniversalSearch
apiReq.HttpMethod = "POST"
apiResp, err := core.Request(ctx, apiReq, a.config, options...)
if err != nil {
a.config.Logger.Error(ctx, fmt.Sprintf("[UniversalSearch] fail to invoke api, error: %v", err.Error()))
return nil, err
}
// 反序列响应结果
resp := &UniversalSearchResp{APIResp: apiResp}
err = apiResp.JSONUnmarshalBody(resp, a.config)
if err != nil {
a.config.Logger.Error(ctx, fmt.Sprintf("[UniversalSearch] fail to unmarshal response body, error: %v", err.Error()))
return nil, err
}
return resp, err
}
86 changes: 86 additions & 0 deletions service/workitem/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type AbortWorkItemReqBody struct {
IsAborted bool `json:"is_aborted"`

Reason string `json:"reason"`

ReasonOption string `json:"reason_option"`
}

type AbortWorkItemResp struct {
Expand All @@ -56,6 +58,7 @@ func NewAbortWorkItemReqBuilder() *AbortWorkItemReqBuilder {
builder.body = &AbortWorkItemReqBody{}
return builder
}

func (builder *AbortWorkItemReqBuilder) ProjectKey(projectKey string) *AbortWorkItemReqBuilder {
builder.apiReq.PathParams.Set("project_key", fmt.Sprint(projectKey))
return builder
Expand All @@ -72,10 +75,17 @@ func (builder *AbortWorkItemReqBuilder) IsAborted(isAborted bool) *AbortWorkItem
builder.body.IsAborted = isAborted
return builder
}

func (builder *AbortWorkItemReqBuilder) Reason(reason string) *AbortWorkItemReqBuilder {
builder.body.Reason = reason
return builder
}

func (builder *AbortWorkItemReqBuilder) ReasonOption(reasonOption string) *AbortWorkItemReqBuilder {
builder.body.ReasonOption = reasonOption
return builder
}

func (builder *AbortWorkItemReqBuilder) Build() *AbortWorkItemReq {
req := &AbortWorkItemReq{}
req.apiReq = builder.apiReq
Expand Down Expand Up @@ -1780,3 +1790,79 @@ func (builder *WbsViewReqBuilder) Build() *WbsViewReq {
req.apiReq.Body = builder.body
return req
}

type UniversalSearchReq struct {
apiReq *core.APIReq
}
type UniversalSearchReqBody struct {
DataSources []DataSource `json:"data_sources,omitempty"`

UserKey *string `json:"user_key,omitempty"`

SearchGroup *SearchGroup `json:"search_group,omitempty"`

Sort *Sort `json:"sort,omitempty"`

Pagination *Pagination `json:"pagination,omitempty"`

FieldSelected []string `json:"field_selected,omitempty"`

Features map[string]string `json:"features,omitempty"`
}

type UniversalSearchResp struct {
*core.APIResp `json:"-"`
core.CodeError
Data *string `json:"data,omitempty"`

Pagination *Pagination `json:"pagination,omitempty"`

ExtraInfo map[string]string `json:"extra_info,omitempty"`
}

type UniversalSearchReqBuilder struct {
apiReq *core.APIReq
}

func NewUniversalSearchReqBuilder() *UniversalSearchReqBuilder {
builder := &UniversalSearchReqBuilder{}
builder.apiReq = &core.APIReq{
PathParams: core.PathParams{},
QueryParams: core.QueryParams{},
Body: &UniversalSearchReqBody{},
}
return builder
}
func (builder *UniversalSearchReqBuilder) DataSources(dataSources []DataSource) *UniversalSearchReqBuilder {
builder.apiReq.Body.(*UniversalSearchReqBody).DataSources = dataSources
return builder
}
func (builder *UniversalSearchReqBuilder) UserKey(userKey *string) *UniversalSearchReqBuilder {
builder.apiReq.Body.(*UniversalSearchReqBody).UserKey = userKey
return builder
}
func (builder *UniversalSearchReqBuilder) SearchGroup(searchGroup *SearchGroup) *UniversalSearchReqBuilder {
builder.apiReq.Body.(*UniversalSearchReqBody).SearchGroup = searchGroup
return builder
}
func (builder *UniversalSearchReqBuilder) Sort(sort *Sort) *UniversalSearchReqBuilder {
builder.apiReq.Body.(*UniversalSearchReqBody).Sort = sort
return builder
}
func (builder *UniversalSearchReqBuilder) Pagination(pagination *Pagination) *UniversalSearchReqBuilder {
builder.apiReq.Body.(*UniversalSearchReqBody).Pagination = pagination
return builder
}
func (builder *UniversalSearchReqBuilder) FieldSelected(fieldSelected []string) *UniversalSearchReqBuilder {
builder.apiReq.Body.(*UniversalSearchReqBody).FieldSelected = fieldSelected
return builder
}
func (builder *UniversalSearchReqBuilder) Features(features map[string]string) *UniversalSearchReqBuilder {
builder.apiReq.Body.(*UniversalSearchReqBody).Features = features
return builder
}
func (builder *UniversalSearchReqBuilder) Build() *UniversalSearchReq {
req := &UniversalSearchReq{}
req.apiReq = builder.apiReq
return req
}
68 changes: 67 additions & 1 deletion service/workitem/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ type Expand struct {
NeedUserDetail bool `json:"need_user_detail"`

NeedSubTaskParent bool `json:"need_sub_task_parent"`

NeedUnionDeliverable bool `json:"need_union_deliverable"`
}

type FieldConf struct {
Expand Down Expand Up @@ -237,7 +239,7 @@ type Schedule struct {
EstimateEndDate *int64 `json:"estimate_end_date,omitempty"`

Owners []string `json:"owners"`

ActualWorkTime *float64 `json:"actual_work_time,omitempty"`

IsAuto *bool `json:"is_auto,omitempty"`
Expand Down Expand Up @@ -399,6 +401,8 @@ type WBSWorkItem struct {
WorkItemTypeKey string `json:"work_item_type_key"`

Milestone bool `json:"milestone"`

UnionDeliverable UnionDeliverable `json:"union_deliverable"`
}

type WbsViewResponse struct {
Expand Down Expand Up @@ -491,6 +495,8 @@ type WorkItemRelation struct {
WorkItemTypeName string `json:"work_item_type_name"`

RelationDetails []*RelationDetail `json:"relation_details"`

RelationType int64 `json:"relation_type"`
}

type WorkItemStatus struct {
Expand Down Expand Up @@ -572,3 +578,63 @@ type WorkflowNode struct {

Participants []string `json:"participants"`
}

type UnionDeliverable struct {
FieldDeliverables []FieldDeliverableItem `json:"field_deliverables"`

InstanceDeliverables []InstanceDeliverableItem `json:"instance_deliverables"`
}

type FieldDeliverableItem struct {
FieldInfo field.FieldValuePair `json:"field_info"`

Placeholder string `json:"placeholder"`

Remark string `json:"remark"`

Status int64 `json:"status"`
}

type InstanceDeliverableItem struct {
Name string `json:"name"`

WorkItemID int64 `json:"work_item_id"`

Deletable bool `json:"deletable"`

MustComplete bool `json:"must_complete"`

StateKey string `json:"state_key"`

StateName string `json:"state_name"`

Owners []string `json:"owners"`

Remark string `json:"remark"`
}

type DataSource struct {
ProjectKey *string `json:"project_key,omitempty"`

WorkItemTypeKeys *string `json:"work_item_type_keys,omitempty"`
}

type Sort struct {
FieldKey *string `json:"field_key,omitempty"`

FieldType *string `json:"field_type,omitempty"`

WorkItemTypeKey *string `json:"work_item_type_key,omitempty"`

Order *string `json:"order,omitempty"`

Params map[string]string `json:"params,omitempty"`
}

type Pagination struct {
PageNum *int64 `json:"page_num,omitempty"`

PageSize *int64 `json:"page_size,omitempty"`

Total *int64 `json:"total,omitempty"`
}