Giter VIP home page Giter VIP logo

oapi-sdk-go's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oapi-sdk-go's Issues

SheetsBatchUpdate方法无法将subSheet的index更新为0

(spreadsheetss *SpreadsheetsService) SheetsBatchUpdate方法无法将subSheet的index更新为0,需要将api-sdk-go/service/sheets/v2/model.go的Properties结构体的字段都改为指针类型,不然omitempty遇到默认值就会忽略掉

审批实例状态变更 v1.0 这个事件能支持处理吗?

这个我查了飞书文档里是没有的,
文档里只有常用审批的(例如请假,补卡等)和审批定义变更的。
我需要的是自建的审批状态更新能处理的,它的event type是approval_instance

在开发者后台里去订阅事件,是可以订阅到这个事件的。

使用多维表格sdk,如果使用描述字段则会触发系统异常。

代码:

	f := NewFeishuClient()
	req := larkbitable.NewListAppTableFieldReqBuilder().
		AppToken("").
		TableId("").
		ViewId("").
		TextFieldAsArray(true).
		PageSize(20).
		Build()
	ctx := context.TODO()
	iterator, err := f.client.Bitable.AppTableField.List(ctx, req)

异常:image

造成原因:使用了描述字段,猜测系统后台struct字段类型不匹配无法unmarshal。

image

尝试修复,删除描述内容后错误依旧。该字段一旦创建删除后也是一个空串,字段还是存在。

open-apis/drive/v1/permissions接口报错

open-apis/drive/v1/permissions接口之前一直都没问题,这两天突然报错
报错信息是:ERROR { Code: -1, Msg: "content-type: text/plain, is not: application/json, body:404 page not found" }
是sdk或者open-api有更新吗?

请求参数写不进请求

如下代码所示,requestParam这个参数设置不到请求里面,最后创建得到的表格没有标题,在debug的时候传入的tittle变量是有值的:

func CreateLarkTable(ctx *core.Context, title string, folderToken string) (path string, err error) {
	httpPath := "https://open.feishu.cn/open-apis/sheets/v3/spreadsheets"
	httpMethod := "POST"
	requestParam := request.SetQueryParams(map[string]interface{}{"title": title, "folder_token": folderToken})
	ret := make(map[string]interface{})
	req := request.NewRequestWithNative(httpPath, httpMethod, accessTokenType, nil, &ret, requestParam)

	err = api.Send(ctx, conf, req)
	if err != nil {
		return "", err
	}

	if _, ok := ret["spreadsheet"]; !ok {
		return "", fmt.Errorf("响应不存在spreadsheet字段")
	}
	spreadsheet := ret["spreadsheet"]
	if _, ok := spreadsheet.(map[string]interface{}); !ok {
		return "", fmt.Errorf("响应的spreadsheet字段不能转换为map[string]interface{}")
	}
	params := spreadsheet.(map[string]interface{})
	if _, ok := params["url"]; !ok {
		return "", fmt.Errorf("响应不存在url字段")
	}
	if _, ok := params["url"].(string); !ok {
		return "", fmt.Errorf("响应的url字段不是string")
	}
	url := params["url"].(string)
	return url, nil
}

搜索文档的openapi

sdk中封装的struct返回值的字段与文档不一致
https://github.com/larksuite/oapi-sdk-go/blob/main/service/suite/v1/model.go/#L12
type DocsEntity struct {
DocsToken string json:"docs_token,omitempty"
DocsType string json:"docs_type,omitempty"
Title string json:"title,omitempty"
DocsOwner string json:"docs_owner,omitempty"
ForceSendFields []string json:"-"
}

sdk中的是 docs_owner,而文档中的是owner_id
https://open.feishu.cn/document/ukTMukTMukTM/ugDM4UjL4ADO14COwgTN

飞书审批的client 的参数 json 设置有问题

type FieldGroup struct {
Writable []string json:"writable,omitempty" // 可写权限的表单项的 id列表
Readable []string json:"readable,omitempty" // 可读权限的表单项的 id列表
}

Writable 如果没有字段需要传,因为有 omitempty 就会报参数没传

unable to send MessageCard via webhook

package main

import (
	"context"
	"fmt"

	"github.com/buger/jsonparser"
	lark "github.com/larksuite/oapi-sdk-go/v2"
)

type cardBody struct {
	Card    lark.MessageCard `json:"card"`
	MsgType string           `json:"msg_type"`
}

func main() {
	customerBot := lark.NewCustomerBot("https://open.feishu.cn/open-apis/bot/v2/hook/4935e6fc-4490-4340-b15e-719cebe96172", "xxxxxxxxxxxxxxxxxxxx")
	card := &lark.MessageCard{
		CardLink: &lark.MessageCardURL{
			URL:        "https://www.feishu.cn",
			AndroidURL: "https://www.feishu.cn",
			IOSURL:     "https://www.feishu.cn",
			PCURL:      "https://www.feishu.cn",
		},
		Config: &lark.MessageCardConfig{EnableForward: lark.BoolPtr(true)},
		Header: &lark.MessageCardHeader{
			Template: lark.StringPtr("blue"),
			Title: &lark.MessageCardPlainText{
				Content: "Header title",
			},
		},
		Elements: []lark.MessageCardElement{
			&lark.MessageCardImage{
				Alt: &lark.MessageCardPlainText{
					Content: "img_v2_9221f258-db3e-4a40-b9cb-24decddee2bg",
					Lines:   nil,
				},
				Title: &lark.MessageCardPlainText{
					Content: "img_v2_9221f258-db3e-4a40-b9cb-24decddee2bg",
				},
				ImgKey:       "img_v2_9221f258-db3e-4a40-b9cb-24decddee2bg",
				CompactWidth: lark.BoolPtr(false),
			},
			&lark.MessageCardAction{
				Actions: []lark.MessageCardActionElement{
					&lark.MessageCardEmbedButton{
						Text: &lark.MessageCardPlainText{
							Content: "button",
						},
						Type:  lark.MessageCardButtonTypeDanger.Ptr(),
						Value: map[string]interface{}{"value": "1"},
						Confirm: &lark.MessageCardActionConfirm{
							Title: &lark.MessageCardPlainText{
								Content: "Title",
							},
							Text: &lark.MessageCardPlainText{
								Content: "Text",
							},
						},
					},
				},
				Layout: lark.MessageCardActionLayoutFlow.Ptr(),
			},
			&lark.MessageCardMarkdown{
				Content: "**Markdown**",
			},
			&lark.MessageCardDiv{
				Text: &lark.MessageCardPlainText{
					Content: "text",
				},
				Extra: &lark.MessageCardEmbedButton{
					Text: &lark.MessageCardPlainText{
						Content: "button",
					},
					Type:  lark.MessageCardButtonTypeDanger.Ptr(),
					Value: map[string]interface{}{"value": "1"},
					Confirm: &lark.MessageCardActionConfirm{
						Title: &lark.MessageCardPlainText{
							Content: "Title",
						},
						Text: &lark.MessageCardPlainText{
							Content: "Text",
						},
					},
				},
			},
		},
	}
	str, err := card.JSON()
	if err != nil {
		panic(err)
	}
	body := []byte(`{"msg_type":"interactive","card":{}}`)
	body, err = jsonparser.Set(body, []byte(str), "card")
	if err != nil {
		panic(err)
	}
	fmt.Printf("%s", body)
	resp, err := customerBot.SendMessage(context.TODO(), "interactive", body)
	if err != nil {
		panic(err)
	}
	fmt.Printf("request id: %s \n", resp.RequestId())
	fmt.Println(lark.Prettify(resp))
}
  CodeError: {
    Code: 19002,
    Msg: "params error, unknown card value"
  }

Cache接口的Set方法的value参数的类型能否用interface{}呢?

飞书SDK的 Cache接口:

type Cache interface {
	Set(ctx context.Context, key string, value string, expireTime time.Duration) error
	Get(ctx context.Context, key string) (string, error)
}

GO语言的 redis包 github.com/go-redis/redis/v8
Set 方法的参数 value 使用的是 interface{} 类型

  func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
	  args := make([]interface{}, 3, 5)
	  args[0] = "set"
	  args[1] = key
	  args[2] = value
	  if expiration > 0 {
		  if usePrecise(expiration) {
			  args = append(args, "px", formatMs(ctx, expiration))
		  } else {
			  args = append(args, "ex", formatSec(ctx, expiration))
		  }
	  } else if expiration == KeepTTL {
		  args = append(args, "keepttl")
	  }
  
	  cmd := NewStatusCmd(ctx, args...)
	  _ = c(ctx, cmd)
	  return cmd
  }

所以在开发的时候,大多数企业或者个人都会封装自己的go-kit工具,统一去定义 Cache接口,然后用redis去实现 Cache接口

/ Cache 缓存相关的实现 .
type Cache interface {
	// Set .
	Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error

	// Get .
	Get(ctx context.Context, key string) (string, error)
}

为了方便大多数项目可能就直接用 interface{} 类型和 redis包保持一致了

func (r *Redis) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
	err := r.client.Set(ctx, key, value, expiration).Err()
	return err
}

func (r *Redis) Get(ctx context.Context, key string) (string, error) {
	value, err := r.client.Get(ctx, key).Result()
	if err != nil && err == redis.Nil {
		return "", errors.ERRMissingCacheKey
	}
	return value, nil
}

然而当我项目用到飞书SDK的时候,我想定制 token 缓存器,使用我已有的redis作为SDK的缓存器,就无法使用,因为我没有实现SDK提供的Cache接口的Set方法
image

当我去实现SDK提供的 Cache接口时,报重名错误

截屏2023-03-24 15 24 11

其实SDK完全也可以使用 interface{}类型,这样就避免了类型不一致而方法同名的情况了

验签用错字段?

image

如图,验签应该是用verificationToken而不是eventEncryptKey?

dispather.go VerifySign函数

MessageCardEmbedSelectMenuStatic.MarshalJSON() only returned 'tag'

package main

import (
	"fmt"
	"github.com/larksuite/oapi-sdk-go/v2"
)

func main() {
	card := lark.MessageCard{
		Header: &lark.MessageCardHeader{
			Title:    &lark.MessageCardPlainText{Content: "k8s ticket"},
			Template: lark.StringPtr("indigo"),
		},
	}
	element := &lark.MessageCardAction{}
	cluster := &lark.MessageCardEmbedSelectMenuStatic{
		&lark.MessageCardEmbedSelectMenuBase{
			Placeholder: &lark.MessageCardPlainText{
				Content: "choose cluster",
			},
			InitialOption: "dev",
		},
	}
	element.Actions = append(element.Actions, cluster)
	card.Elements = append(card.Elements, element)
	content, err := card.JSON()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("card:%s\n", content)
}

out:
card:{"header":{"template":"indigo","title":{"content":"k8s ticket","tag":"plain_text"}},"elements":[{"actions":[{"tag":"select_static"}],"tag":"action"}]}

Embedded struct without json tag would be ignored at

jsonTag := st.Field(i).Tag.Get("json")

请教使用gin框架,用何种正确姿势的食用方法!跪求大佬!

Log级别为Debug

代码如下:
//飞书中EncryptKey为空
AppSet := config.NewInternalAppSettings(AppID, AppSecret, Verification, Encrypt)
FeiShuConf = config.NewConfigWithDefaultStore(constants.DomainFeiShu, AppSet, log.NewDefaultLogger(), log.LevelDebug)

func Event(ctx *gin.Context) {

im.SetMessageReceiveEventHandler(FeiShuConf, func(ctx *core.Context, event *im.MessageReceiveEvent) error {
	fmt.Println("**************** SetMessageReceiveEventHandler ****************")
	fmt.Println("GetID: ", ctx.GetRequestID())
	fmt.Println("SetMessageReceiveEventHandler", tools.Prettify(event))
	return nil
})
eventhttp.Handle(FeiShuConf, ctx.Request, ctx.Writer)

}

请问如何拿到 event?或 直接在 im.SetMessageReceiveEventHandler中使用?
获取event内数据只能通过tools.Prettify(event.Event)吗?

路径参数设置不到请求

路径参数设置不到不请求里面,自己拼接路径参数却执行成功了,应该是路径参数设置失败。以下是自己修改飞书表格权限的代码。还麻烦同学帮忙看下

func OpenLarkTableEditAuthority(ctx *core.Context, token string) (err error) {
	httpPath := "https://open.feishu.cn/open-apis/drive/v1/permissions/:token/public"
	httpMethod := "PATCH"
	requestParam := request.SetQueryParams(map[string]interface{}{"type": "sheet"})
        //路径参数设置生效
	pathParam:=request.SetPathParams(map[string]interface{}{"token":token})
	body := map[string]interface{}{
		"external_access":   true,              //是否允许分享到租户外开关
		"security_entity":   "anyone_can_view", //可创建副本/打印/导出/复制设置 所有可访问此文档的用户
		"comment_entity":    "anyone_can_view", //可评论设置 所有可访问此文档的用户
		"share_entity":      "anyone",          //谁可以添加和管理协作者 所有可阅读或编辑此文档的用户
		"link_share_entity": "anyone_editable", //链接共享 得链接的任何人可编辑(仅external_access=“true”时有效)
		"invite_external":   true,              //非所有权限者/所有者是否允许邀请外部人
	}
	req := request.NewRequestWithNative(httpPath, httpMethod, accessTokenType, body, nil,requestParam,pathParam)

	err = api.Send(ctx, conf, req)

	if err != nil {
		return err
	}
	return nil
}


执行报错:path:https://open.feishu.cn/open-apis/drive/v1/permissions/:token/public, var name: not find value

EventHandle无法获取http request中传入的context

EventHandle无法获取http request中传入的context:

文件 core/httpserverext/httpserverext.go 中

func doProcess(writer http.ResponseWriter, req *http.Request, reqHandler larkevent.IReqHandler) {
	// 转换http请求对象为标准请求对象
	ctx := context.Background()
	eventReq, err := translate(ctx, req)
	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		writer.Write([]byte(err.Error()))
		return
	}

	// 处理请求
	eventResp := reqHandler.Handle(ctx, eventReq)

	// 回写结果
	err = write(ctx, writer, eventResp)
	if err != nil {
		reqHandler.Logger().Error(ctx, fmt.Sprintf("write resp result error:%s", err.Error()))
	}
}

由于 ctx := context.Background(),无法获取 http 中间件中对ctx写入的参数,建议改成 ctx := req.Context()。

获取不到 departments 部门列表

按照SDK+飞书服务端文档规定访问无法获取到部门列表
用POSTMAN脚本可以获取到

怀疑 "parent_department_id": "", 传送写的不对。请问应该怎么传空?

func GetDepartments() {

body := map[string]interface{}{
	"user_id_type": "open_id",
	"department_id_type": "open_department_id",
	"parent_department_id": "",
	"fetch_child":true,
	//"page_token":"",
	//"page_size":50,
}

//接收返回
ret := make(map[string]interface{})

    //构建访问
req := request.NewRequestWithNative("/open-apis/contact/v3/departments", "GET", request.AccessTokenTypeTenant, body, &ret)

//上下文
coreCtx := core.WrapContext(context.Background())

    //发送数据
err := api.Send(coreCtx, FeiShuConf, req)
if err != nil{
	e := err.(*response.Error)
	fmt.Println("发送给自己错误:", e, tools.Prettify(err))
	return
}
fmt.Println("发送给自己:", tools.Prettify(ret))

}

返回:
发送给自己: {
has_more: false,
items: [map[department_id:0 member_count:190 name: open_department_id:0]]
}

文件结构建议

github.com/larksuite/oapi-sdk-go/service/im/v1/api.go
以Service和MessageService的关系为例
Service依赖MessageService,MessageService又依赖于Service,这种实现方式的好处在于可以在MessageService中调用其他服务,缺点是这样会导致Service和MessageService不能分开只能放到一个文件中,分开到不同文件中就会报循环依赖错误,如果继续以这种结构写下去,后续接口越来越来多,该文件就会越来越大,越来越臃肿。
建议将MessageService由继承Service改为只实现config.Config。
各服务保持独一,后续的服务与服务间的调用由使用者来实现

下载图片示例缺少参数

下载文件的示例调用的时候会报错,提示参数错误。

Screen Shot 2021-07-13 at 12 42 31

需要在这个参数里加上operator。 像这样 request.SetQueryParams(map[string]interface{}{"image_key": imageKey, "operator": "app"})

频繁出现read tcp 10.231.29.218:41360->23.212.248.148:443: read: connection reset by peer

Error: fail to client.Im.Chat.Delete: Delete "https://open.feishu.cn/open-apis/im/v1/chats/oc_f63f7aac836c409bb50629b81e839667": read tcp 10.231.29.218:41360->23.212.248.148:443: read: connection reset by peer

Error: fail to client.Im.Chat.Delete: Post "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal": read tcp 10.231.29.190:46648->23.12.144.194:443: read: connection reset by peer

我是boei18n的集群,跟部署环境有关系吗?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.