From d7052aeb9668763dd2282e5ee125e89d59535667 Mon Sep 17 00:00:00 2001 From: Ceelog Date: Wed, 19 Aug 2020 19:46:05 +0800 Subject: [PATCH] rebuild --- .../{appinfo => app}/app_manage/app_manage.go | 30 +- .../app_manage/app_manage_test.go | 32 +- .../app_manage/example_app_manage_test.go | 10 +- .../app_store/app_store.go} | 35 +- .../app_store/app_store_test.go} | 47 +- .../app_store/example_app_store_test.go} | 19 +- apis/authen/authen.go | 303 +++++ apis/bot/bot_manage/bot_manage.go | 12 +- apis/bot/bot_manage/bot_manage_test.go | 12 +- .../bot/bot_manage/example_bot_manage_test.go | 2 - .../group_manage/example_group_manage_test.go | 9 +- apis/bot/group_manage/group_manage.go | 30 +- apis/bot/group_manage/group_manage_test.go | 32 +- .../approve.go => approval/approval.go} | 190 ++- .../approval_test.go} | 154 ++- .../example_approval_test.go} | 66 +- apis/capabilities/calendar/calendar.go | 212 ++- apis/capabilities/calendar/calendar_test.go | 256 +++- .../calendar/example_calendar_test.go | 68 +- apis/capabilities/document/comment/comment.go | 34 + .../document/comment/comment_test.go | 54 + .../document/comment/example_comment_test.go | 18 + apis/capabilities/document/docs/docs.go | 90 ++ apis/capabilities/document/docs/docs_test.go | 132 ++ .../document/docs/example_docs_test.go | 39 + apis/capabilities/document/document.go | 749 ---------- apis/capabilities/document/document_test.go | 1211 ----------------- .../document/example_document_test.go | 345 ----- .../document/file/example_file_test.go | 41 + apis/capabilities/document/file/file.go | 95 ++ apis/capabilities/document/file/file_test.go | 134 ++ .../document/folder/example_folder_test.go | 49 + apis/capabilities/document/folder/folder.go | 112 ++ .../document/folder/folder_test.go | 170 +++ .../permission/example_permission_test.go | 78 ++ .../document/permission/permission.go | 168 +++ .../document/permission/permission_test.go | 276 ++++ .../platform/example_platform_test.go | 28 + .../document/platform/platform.go | 56 + .../document/platform/platform_test.go | 91 ++ .../document/sheets/example_sheets_test.go | 203 +++ apis/capabilities/document/sheets/sheets.go | 485 +++++++ .../document/sheets/sheets_test.go | 716 ++++++++++ .../example_meeting_room_test.go} | 51 +- .../meeting_room.go} | 68 +- .../meeting_room_test.go} | 66 +- apis/contact/async_batch/async_batch.go | 12 +- apis/contact/async_batch/async_batch_test.go | 12 +- .../async_batch/example_async_batch_test.go | 3 - apis/contact/contact.go | 4 +- apis/contact/contact_test.go | 4 +- apis/contact/department/department.go | 48 +- apis/contact/department/department_test.go | 72 +- .../department/example_department_test.go | 30 +- apis/contact/user/example_user_test.go | 14 +- apis/contact/user/user.go | 48 +- apis/contact/user/user_test.go | 52 +- apis/message/example_message_test.go | 16 - apis/message/message.go | 65 +- apis/message/message_test.go | 60 +- apis/user_group/example_user_group_test.go | 3 - apis/user_group/user_group.go | 12 +- apis/user_group/user_group_test.go | 12 +- client.go | 89 +- cmd/apiconfig.go | 85 +- cmd/apiconfig2.go | 316 ++++- cmd/build.go | 97 +- cmd/tpl/ImagePut.tpl | 40 + cmd/tpl/Upload.tpl | 45 + doc/apilist.md | 223 +-- feishu.go | 4 +- go.mod | 7 +- go.sum | 27 +- internal_app.go | 12 +- public_app.go | 10 +- test/test.go | 17 +- 76 files changed, 5294 insertions(+), 3223 deletions(-) rename apis/{appinfo => app}/app_manage/app_manage.go (83%) rename apis/{appinfo => app}/app_manage/app_manage_test.go (89%) rename apis/{appinfo => app}/app_manage/example_app_manage_test.go (93%) rename apis/{appinfo/appstore/appstore.go => app/app_store/app_store.go} (57%) rename apis/{appinfo/appstore/appstore_test.go => app/app_store/app_store_test.go} (67%) rename apis/{appinfo/appstore/example_appstore_test.go => app/app_store/example_app_store_test.go} (73%) create mode 100644 apis/authen/authen.go rename apis/capabilities/{approve/approve.go => approval/approval.go} (60%) rename apis/capabilities/{approve/approve_test.go => approval/approval_test.go} (76%) rename apis/capabilities/{approve/example_approve_test.go => approval/example_approval_test.go} (63%) create mode 100644 apis/capabilities/document/comment/comment.go create mode 100644 apis/capabilities/document/comment/comment_test.go create mode 100644 apis/capabilities/document/comment/example_comment_test.go create mode 100644 apis/capabilities/document/docs/docs.go create mode 100644 apis/capabilities/document/docs/docs_test.go create mode 100644 apis/capabilities/document/docs/example_docs_test.go delete mode 100644 apis/capabilities/document/document.go delete mode 100644 apis/capabilities/document/document_test.go delete mode 100644 apis/capabilities/document/example_document_test.go create mode 100644 apis/capabilities/document/file/example_file_test.go create mode 100644 apis/capabilities/document/file/file.go create mode 100644 apis/capabilities/document/file/file_test.go create mode 100644 apis/capabilities/document/folder/example_folder_test.go create mode 100644 apis/capabilities/document/folder/folder.go create mode 100644 apis/capabilities/document/folder/folder_test.go create mode 100644 apis/capabilities/document/permission/example_permission_test.go create mode 100644 apis/capabilities/document/permission/permission.go create mode 100644 apis/capabilities/document/permission/permission_test.go create mode 100644 apis/capabilities/document/platform/example_platform_test.go create mode 100644 apis/capabilities/document/platform/platform.go create mode 100644 apis/capabilities/document/platform/platform_test.go create mode 100644 apis/capabilities/document/sheets/example_sheets_test.go create mode 100644 apis/capabilities/document/sheets/sheets.go create mode 100644 apis/capabilities/document/sheets/sheets_test.go rename apis/capabilities/{meeting/example_meeting_test.go => meeting_room/example_meeting_room_test.go} (70%) rename apis/capabilities/{meeting/meeting.go => meeting_room/meeting_room.go} (82%) rename apis/capabilities/{meeting/meeting_test.go => meeting_room/meeting_room_test.go} (90%) create mode 100644 cmd/tpl/ImagePut.tpl create mode 100644 cmd/tpl/Upload.tpl diff --git a/apis/appinfo/app_manage/app_manage.go b/apis/app/app_manage/app_manage.go similarity index 83% rename from apis/appinfo/app_manage/app_manage.go rename to apis/app/app_manage/app_manage.go index c73473d..889be59 100644 --- a/apis/appinfo/app_manage/app_manage.go +++ b/apis/app/app_manage/app_manage.go @@ -44,7 +44,7 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/uITN1EjLyUTNx4iM1UTM GET https://open.feishu.cn/open-apis/application/v3/is_user_admin */ -func IsUserAdmin(ctx *feishu.App) (resp []byte, err error) { +func IsUserAdmin(ctx *feishu.App, params url.Values) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -52,9 +52,9 @@ func IsUserAdmin(ctx *feishu.App) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiIsUserAdmin, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiIsUserAdmin+"?"+params.Encode(), header) } /* @@ -76,9 +76,9 @@ func AdminScopeGet(ctx *feishu.App, params url.Values) (resp []byte, err error) } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiAdminScopeGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiAdminScopeGet+"?"+params.Encode(), header) } /* @@ -100,9 +100,9 @@ func AppVisibility(ctx *feishu.App, params url.Values) (resp []byte, err error) } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiAppVisibility+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiAppVisibility+"?"+params.Encode(), header) } /* @@ -124,9 +124,9 @@ func VisibleApps(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiVisibleApps+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiVisibleApps+"?"+params.Encode(), header) } /* @@ -148,9 +148,9 @@ func AppList(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiAppList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiAppList+"?"+params.Encode(), header) } /* @@ -172,9 +172,9 @@ func UpdateVisibility(ctx *feishu.App, payload []byte) (resp []byte, err error) } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiUpdateVisibility, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiUpdateVisibility, bytes.NewReader(payload), header) } /* @@ -200,7 +200,7 @@ func AppAdminUserList(ctx *feishu.App) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiAppAdminUserList, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiAppAdminUserList, header) } diff --git a/apis/appinfo/app_manage/app_manage_test.go b/apis/app/app_manage/app_manage_test.go similarity index 89% rename from apis/appinfo/app_manage/app_manage_test.go rename to apis/app/app_manage/app_manage_test.go index 11ee6df..67897bc 100644 --- a/apis/appinfo/app_manage/app_manage_test.go +++ b/apis/app/app_manage/app_manage_test.go @@ -35,12 +35,14 @@ func TestIsUserAdmin(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiIsUserAdmin, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiIsUserAdmin, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App + + params url.Values } tests := []struct { name string @@ -53,7 +55,7 @@ func TestIsUserAdmin(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := IsUserAdmin(tt.args.ctx) + gotResp, err := IsUserAdmin(tt.args.ctx, tt.args.params) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { t.Errorf("IsUserAdmin() error = %v, wantErr %v", err, tt.wantErr) @@ -70,9 +72,9 @@ func TestAdminScopeGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAdminScopeGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAdminScopeGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -107,9 +109,9 @@ func TestAppVisibility(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAppVisibility, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAppVisibility, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -144,9 +146,9 @@ func TestVisibleApps(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiVisibleApps, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiVisibleApps, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -181,9 +183,9 @@ func TestAppList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAppList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAppList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -218,9 +220,9 @@ func TestUpdateVisibility(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiUpdateVisibility, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiUpdateVisibility, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -254,9 +256,9 @@ func TestAppAdminUserList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAppAdminUserList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAppAdminUserList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App diff --git a/apis/appinfo/app_manage/example_app_manage_test.go b/apis/app/app_manage/example_app_manage_test.go similarity index 93% rename from apis/appinfo/app_manage/example_app_manage_test.go rename to apis/app/app_manage/example_app_manage_test.go index 66a4e49..43aa8bf 100644 --- a/apis/appinfo/app_manage/example_app_manage_test.go +++ b/apis/app/app_manage/example_app_manage_test.go @@ -19,13 +19,14 @@ import ( "net/url" "github.com/fastwego/feishu" - "github.com/fastwego/feishu/apis/appinfo/app_manage" + "github.com/fastwego/feishu/apis/app/app_manage" ) func ExampleIsUserAdmin() { var ctx *feishu.App - resp, err := app_manage.IsUserAdmin(ctx) + params := url.Values{} + resp, err := app_manage.IsUserAdmin(ctx, params) fmt.Println(resp, err) } @@ -34,7 +35,6 @@ func ExampleAdminScopeGet() { var ctx *feishu.App params := url.Values{} - resp, err := app_manage.AdminScopeGet(ctx, params) fmt.Println(resp, err) @@ -44,7 +44,6 @@ func ExampleAppVisibility() { var ctx *feishu.App params := url.Values{} - resp, err := app_manage.AppVisibility(ctx, params) fmt.Println(resp, err) @@ -54,7 +53,6 @@ func ExampleVisibleApps() { var ctx *feishu.App params := url.Values{} - resp, err := app_manage.VisibleApps(ctx, params) fmt.Println(resp, err) @@ -64,7 +62,6 @@ func ExampleAppList() { var ctx *feishu.App params := url.Values{} - resp, err := app_manage.AppList(ctx, params) fmt.Println(resp, err) @@ -74,7 +71,6 @@ func ExampleUpdateVisibility() { var ctx *feishu.App payload := []byte("{}") - resp, err := app_manage.UpdateVisibility(ctx, payload) fmt.Println(resp, err) diff --git a/apis/appinfo/appstore/appstore.go b/apis/app/app_store/app_store.go similarity index 57% rename from apis/appinfo/appstore/appstore.go rename to apis/app/app_store/app_store.go index 8bb758f..562b775 100644 --- a/apis/appinfo/appstore/appstore.go +++ b/apis/app/app_store/app_store.go @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package appstore 应用信息/应用商店 -package appstore +// Package app_store 应用信息/应用商店 +package app_store import ( "net/http" @@ -23,10 +23,33 @@ import ( ) const ( + apiCheckUser = "/open-apis/pay/v1/paid_scope/check_user" apiOrderList = "/open-apis/pay/v1/order/list" apiOrderGet = "/open-apis/pay/v1/order/get" ) +/* +查询用户是否在应用开通范围 + +该接口用于查询用户是否在企业管理员设置的使用该应用的范围中。如果设置的付费套餐是按人收费或者限制了最大人数,开放平台会引导企业管理员设置“付费功能开通范围”,本接口用于查询用户是否在企业管理员设置的使用该应用的范围中,可以通过此接口,在付费功能点入口判断是否允许某个用户进入使用。 + +See: https://open.feishu.cn/document/ukTMukTMukTM/uATNwUjLwUDM14CM1ATN + +GET https://open.feishu.cn/open-apis/pay/v1/paid_scope/check_user?open_id=ou_5ad573a6411d72b8305fda3a9c15c70e +*/ +func CheckUser(ctx *feishu.App, params url.Values) (resp []byte, err error) { + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiCheckUser+"?"+params.Encode(), header) +} + /* 查询租户购买的付费方案 @@ -45,9 +68,9 @@ func OrderList(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiOrderList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiOrderList+"?"+params.Encode(), header) } /* @@ -68,7 +91,7 @@ func OrderGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiOrderGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiOrderGet+"?"+params.Encode(), header) } diff --git a/apis/appinfo/appstore/appstore_test.go b/apis/app/app_store/app_store_test.go similarity index 67% rename from apis/appinfo/appstore/appstore_test.go rename to apis/app/app_store/app_store_test.go index b323895..81b5d86 100644 --- a/apis/appinfo/appstore/appstore_test.go +++ b/apis/app/app_store/app_store_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package appstore +package app_store import ( "net/http" @@ -30,14 +30,51 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestCheckUser(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiCheckUser, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := CheckUser(tt.args.ctx, tt.args.params) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("CheckUser() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("CheckUser() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} func TestOrderList(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiOrderList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiOrderList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -72,9 +109,9 @@ func TestOrderGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiOrderGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiOrderGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App diff --git a/apis/appinfo/appstore/example_appstore_test.go b/apis/app/app_store/example_app_store_test.go similarity index 73% rename from apis/appinfo/appstore/example_appstore_test.go rename to apis/app/app_store/example_app_store_test.go index 0077a84..a80c5e7 100644 --- a/apis/appinfo/appstore/example_appstore_test.go +++ b/apis/app/app_store/example_app_store_test.go @@ -12,22 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -package appstore_test +package app_store_test import ( "fmt" "net/url" "github.com/fastwego/feishu" - "github.com/fastwego/feishu/apis/appinfo/appstore" + "github.com/fastwego/feishu/apis/app/app_store" ) -func ExampleOrderList() { +func ExampleCheckUser() { var ctx *feishu.App params := url.Values{} + resp, err := app_store.CheckUser(ctx, params) - resp, err := appstore.OrderList(ctx, params) + fmt.Println(resp, err) +} + +func ExampleOrderList() { + var ctx *feishu.App + + params := url.Values{} + resp, err := app_store.OrderList(ctx, params) fmt.Println(resp, err) } @@ -36,8 +44,7 @@ func ExampleOrderGet() { var ctx *feishu.App params := url.Values{} - - resp, err := appstore.OrderGet(ctx, params) + resp, err := app_store.OrderGet(ctx, params) fmt.Println(resp, err) } diff --git a/apis/authen/authen.go b/apis/authen/authen.go new file mode 100644 index 0000000..aaa5030 --- /dev/null +++ b/apis/authen/authen.go @@ -0,0 +1,303 @@ +// Copyright 2020 FastWeGo +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package authen 身份认证 + +/* +网页授权流程分为四步: + +整体流程 +第一步: 网页后端发现用户未登录,请求身份验证; +第二步: 用户登录后,开放平台生成登录预授权码,302跳转至重定向地址; +第三步: 网页后端调用获取登录用户身份校验登录预授权码合法性,获取到用户身份; +第四步: 如需其他用户信息,网页后端可调用获取用户信息(身份验证)。 +*/ +package authen + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + + "github.com/fastwego/feishu" +) + +const ( + apiGetRedirectUri = "/open-apis/authen/v1/index" + apiGetAccessToken = "/open-apis/authen/v1/access_token" + apiRefreshAccessToken = "/open-apis/authen/v1/refresh_access_token" + apiGetUserInfo = "/open-apis/authen/v1/user_info" + apiCode2Session = "/open-apis/mina/v2/tokenLoginValidate" +) + +/* +请求身份验证 + +应用请求用户身份验证时,需按如下方式构造登录链接,并引导用户跳转至此链接。飞书客户端内用户免登,系统浏览器内用户需完成扫码登录。登录成功后会生成登录预授权码 code,并作为参数重定向到重定向URL。 + +See: https://open.feishu.cn/document/ukTMukTMukTM/ukzN4UjL5cDO14SO3gTN + +GET https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri={REDIRECT_URI}&app_id={APPID}&state={STATE} +*/ +func GetRedirectUri(app_id string, redirectUri string, state string) (authorizeUrl string) { + params := url.Values{} + params.Add("app_id", app_id) + params.Add("redirectUri", redirectUri) + params.Add("state", state) + return feishu.FeishuServerUrl + apiGetRedirectUri + "?" + params.Encode() +} + +type AccessToken struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + AccessToken string `json:"access_token"` + AvatarURL string `json:"avatar_url"` + AvatarThumb string `json:"avatar_thumb"` + AvatarMiddle string `json:"avatar_middle"` + AvatarBig string `json:"avatar_big"` + ExpiresIn int `json:"expires_in"` + Name string `json:"name"` + EnName string `json:"en_name"` + OpenID string `json:"open_id"` + TenantKey string `json:"tenant_key"` + RefreshExpiresIn int `json:"refresh_expires_in"` + RefreshToken string `json:"refresh_token"` + TokenType string `json:"token_type"` + } `json:"data"` +} + +/* +获取登录用户身份 + +通过此接口获取登录预授权码 code 对应的登录用户身份。 + +See: https://open.feishu.cn/document/ukTMukTMukTM/uEDO4UjLxgDO14SM4gTN + +POST https://open.feishu.cn/open-apis/authen/v1/access_token +*/ +func GetAccessToken(app_access_token string, code string) (accessTokenResp AccessToken, err error) { + + params := struct { + AppAccessToken string `json:"app_access_token"` + GrantType string `json:"grant_type"` + Code string `json:"code"` + }{ + AppAccessToken: app_access_token, + GrantType: "authorization_code", + Code: code, + } + + data, err := json.Marshal(params) + if err != nil { + return + } + + response, err := http.Post(feishu.FeishuServerUrl+apiGetAccessToken, "application/json", bytes.NewReader(data)) + if err != nil { + return + } + + defer response.Body.Close() + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return + } + + err = json.Unmarshal(body, &accessTokenResp) + if err != nil { + err = fmt.Errorf("%s", string(body)) + return + } + + return +} + +/* +刷新 access_token + +该接口用于在 access_token 过期时用 refresh_token 重新获取 access_token。此时会返回新的 refresh_token,再次刷新 access_token 时需要使用新的 refresh_token。 + +See: https://open.feishu.cn/document/ukTMukTMukTM/uQDO4UjL0gDO14CN4gTN + +POST https://open.feishu.cn/open-apis/authen/v1/refresh_access_token +*/ +func RefreshAccessToken(app_access_token string, refresh_token string) (accessTokenResp AccessToken, err error) { + params := struct { + AppAccessToken string `json:"app_access_token"` + GrantType string `json:"grant_type"` + RefreshToken string `json:"refresh_token"` + }{ + AppAccessToken: app_access_token, + GrantType: "refresh_token", + RefreshToken: refresh_token, + } + + data, err := json.Marshal(params) + if err != nil { + return + } + + response, err := http.Post(feishu.FeishuServerUrl+apiRefreshAccessToken, "application/json", bytes.NewReader(data)) + if err != nil { + return + } + + defer response.Body.Close() + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return + } + + err = json.Unmarshal(body, &accessTokenResp) + if err != nil { + err = fmt.Errorf("%s", string(body)) + return + } + + return +} + +type UserInfo struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + Name string `json:"name"` + AvatarURL string `json:"avatar_url"` + AvatarThumb string `json:"avatar_thumb"` + AvatarMiddle string `json:"avatar_middle"` + AvatarBig string `json:"avatar_big"` + Email string `json:"email"` + UserID string `json:"user_id"` + Mobile string `json:"mobile"` + Status int `json:"status"` + } `json:"data"` +} + +/* +获取用户信息(身份验证) + +此接口仅用于获取登录用户的信息。调用此接口需要在 Header 中带上 user_access_token。 + +See: https://open.feishu.cn/document/ukTMukTMukTM/uIDO4UjLygDO14iM4gTN + +GET https://open.feishu.cn/open-apis/authen/v1/user_info +*/ +func GetUserInfo(access_token string) (userInfo UserInfo, err error) { + header := http.Header{} + header.Set("Authorization", "Bearer "+access_token) + header.Set("Content-Type", "application/json") + + request, err := http.NewRequest(http.MethodGet, feishu.FeishuServerUrl+apiGetUserInfo, nil) + if err != nil { + return + } + + request.Header = header + + c := &http.Client{} + response, err := c.Do(request) + if err != nil { + return + } + + defer response.Body.Close() + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return + } + + err = json.Unmarshal(body, &userInfo) + if err != nil { + err = fmt.Errorf("%s", string(body)) + return + } + + return +} + +type Session struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + UID string `json:"uid"` + OpenID string `json:"open_id"` + UnionID string `json:"union_id"` + SessionKey string `json:"session_key"` + TenantKey string `json:"tenant_key"` + EmployeeID string `json:"employee_id"` + TokenType string `json:"token_type"` + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + RefreshToken string `json:"refresh_token"` + } `json:"data"` +} + +/* +code2session + +本接口应在后端服务器调用 + +通过 login 接口获取到登录凭证后,开发者可以通过服务器发送请求的方式获取 session_key 和 openId + +See: https://open.feishu.cn/document/uYjL24iN/ukjM04SOyQjL5IDN + +POST https://open.feishu.cn/open-apis/mina/v2/tokenLoginValidate +*/ +func Code2Session(app_access_token string, code string) (sess Session, err error) { + header := http.Header{} + header.Set("Authorization", "Bearer "+app_access_token) + header.Set("Content-Type", "application/json") + + co := struct { + Code string `json:"code"` + }{ + Code: code, + } + + data, err := json.Marshal(co) + if err != nil { + return + } + + request, err := http.NewRequest(http.MethodPost, feishu.FeishuServerUrl+apiCode2Session, bytes.NewReader(data)) + if err != nil { + return + } + + request.Header = header + + c := &http.Client{} + response, err := c.Do(request) + if err != nil { + return + } + + defer response.Body.Close() + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return + } + + err = json.Unmarshal(body, &sess) + if err != nil { + err = fmt.Errorf("%s", string(body)) + return + } + + return +} diff --git a/apis/bot/bot_manage/bot_manage.go b/apis/bot/bot_manage/bot_manage.go index 0d05f40..63b6c16 100644 --- a/apis/bot/bot_manage/bot_manage.go +++ b/apis/bot/bot_manage/bot_manage.go @@ -48,9 +48,9 @@ func Info(ctx *feishu.App) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiInfo, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiInfo, header) } /* @@ -73,9 +73,9 @@ func Add(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiAdd, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiAdd, bytes.NewReader(payload), header) } /* @@ -98,7 +98,7 @@ func Remove(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiRemove, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiRemove, bytes.NewReader(payload), header) } diff --git a/apis/bot/bot_manage/bot_manage_test.go b/apis/bot/bot_manage/bot_manage_test.go index ffeb664..56cb0ff 100644 --- a/apis/bot/bot_manage/bot_manage_test.go +++ b/apis/bot/bot_manage/bot_manage_test.go @@ -34,9 +34,9 @@ func TestInfo(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiInfo, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiInfo, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -69,9 +69,9 @@ func TestAdd(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAdd, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAdd, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -105,9 +105,9 @@ func TestRemove(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiRemove, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiRemove, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App diff --git a/apis/bot/bot_manage/example_bot_manage_test.go b/apis/bot/bot_manage/example_bot_manage_test.go index b8144be..7e09dc0 100644 --- a/apis/bot/bot_manage/example_bot_manage_test.go +++ b/apis/bot/bot_manage/example_bot_manage_test.go @@ -33,7 +33,6 @@ func ExampleAdd() { var ctx *feishu.App payload := []byte("{}") - resp, err := bot_manage.Add(ctx, payload) fmt.Println(resp, err) @@ -43,7 +42,6 @@ func ExampleRemove() { var ctx *feishu.App payload := []byte("{}") - resp, err := bot_manage.Remove(ctx, payload) fmt.Println(resp, err) diff --git a/apis/bot/group_manage/example_group_manage_test.go b/apis/bot/group_manage/example_group_manage_test.go index e492472..1bba4cc 100644 --- a/apis/bot/group_manage/example_group_manage_test.go +++ b/apis/bot/group_manage/example_group_manage_test.go @@ -26,7 +26,6 @@ func ExampleChatCreate() { var ctx *feishu.App payload := []byte("{}") - resp, err := group_manage.ChatCreate(ctx, payload) fmt.Println(resp, err) @@ -35,7 +34,8 @@ func ExampleChatCreate() { func ExampleChatList() { var ctx *feishu.App - resp, err := group_manage.ChatList(ctx) + params := url.Values{} + resp, err := group_manage.ChatList(ctx, params) fmt.Println(resp, err) } @@ -44,7 +44,6 @@ func ExampleChatInfo() { var ctx *feishu.App params := url.Values{} - resp, err := group_manage.ChatInfo(ctx, params) fmt.Println(resp, err) @@ -54,7 +53,6 @@ func ExampleChatUpdate() { var ctx *feishu.App payload := []byte("{}") - resp, err := group_manage.ChatUpdate(ctx, payload) fmt.Println(resp, err) @@ -64,7 +62,6 @@ func ExampleChatterAdd() { var ctx *feishu.App payload := []byte("{}") - resp, err := group_manage.ChatterAdd(ctx, payload) fmt.Println(resp, err) @@ -74,7 +71,6 @@ func ExampleChatterDelete() { var ctx *feishu.App payload := []byte("{}") - resp, err := group_manage.ChatterDelete(ctx, payload) fmt.Println(resp, err) @@ -84,7 +80,6 @@ func ExampleDisband() { var ctx *feishu.App payload := []byte("{}") - resp, err := group_manage.Disband(ctx, payload) fmt.Println(resp, err) diff --git a/apis/bot/group_manage/group_manage.go b/apis/bot/group_manage/group_manage.go index 800c6a7..823b633 100644 --- a/apis/bot/group_manage/group_manage.go +++ b/apis/bot/group_manage/group_manage.go @@ -53,9 +53,9 @@ func ChatCreate(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiChatCreate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiChatCreate, bytes.NewReader(payload), header) } /* @@ -70,7 +70,7 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/uITO5QjLykTO04iM5kDN GET https://open.feishu.cn/open-apis/chat/v4/list */ -func ChatList(ctx *feishu.App) (resp []byte, err error) { +func ChatList(ctx *feishu.App, params url.Values) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -78,9 +78,9 @@ func ChatList(ctx *feishu.App) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiChatList, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiChatList+"?"+params.Encode(), header) } /* @@ -103,9 +103,9 @@ func ChatInfo(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiChatInfo+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiChatInfo+"?"+params.Encode(), header) } /* @@ -128,9 +128,9 @@ func ChatUpdate(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiChatUpdate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiChatUpdate, bytes.NewReader(payload), header) } /* @@ -153,9 +153,9 @@ func ChatterAdd(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiChatterAdd, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiChatterAdd, bytes.NewReader(payload), header) } /* @@ -178,9 +178,9 @@ func ChatterDelete(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiChatterDelete, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiChatterDelete, bytes.NewReader(payload), header) } /* @@ -203,7 +203,7 @@ func Disband(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiDisband, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiDisband, bytes.NewReader(payload), header) } diff --git a/apis/bot/group_manage/group_manage_test.go b/apis/bot/group_manage/group_manage_test.go index 1e69bb2..2df5e07 100644 --- a/apis/bot/group_manage/group_manage_test.go +++ b/apis/bot/group_manage/group_manage_test.go @@ -35,9 +35,9 @@ func TestChatCreate(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiChatCreate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiChatCreate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -71,12 +71,14 @@ func TestChatList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiChatList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiChatList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App + + params url.Values } tests := []struct { name string @@ -89,7 +91,7 @@ func TestChatList(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := ChatList(tt.args.ctx) + gotResp, err := ChatList(tt.args.ctx, tt.args.params) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { t.Errorf("ChatList() error = %v, wantErr %v", err, tt.wantErr) @@ -106,9 +108,9 @@ func TestChatInfo(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiChatInfo, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiChatInfo, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -143,9 +145,9 @@ func TestChatUpdate(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiChatUpdate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiChatUpdate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -179,9 +181,9 @@ func TestChatterAdd(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiChatterAdd, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiChatterAdd, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -215,9 +217,9 @@ func TestChatterDelete(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiChatterDelete, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiChatterDelete, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -251,9 +253,9 @@ func TestDisband(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDisband, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDisband, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App diff --git a/apis/capabilities/approve/approve.go b/apis/capabilities/approval/approval.go similarity index 60% rename from apis/capabilities/approve/approve.go rename to apis/capabilities/approval/approval.go index 37b1803..4a9ee3a 100644 --- a/apis/capabilities/approve/approve.go +++ b/apis/capabilities/approval/approval.go @@ -12,12 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package approve 审批 -package approve +// Package approval 审批 +package approval import ( "bytes" + "io" + "mime/multipart" "net/http" + "net/url" + "os" + "path" "github.com/fastwego/feishu" ) @@ -32,8 +37,11 @@ const ( apiTransfer = "/approval/openapi/v2/instance/transfer" apiCancel = "/approval/openapi/v2/instance/cancel" apiUpload = "/approval/openapi/v2/file/upload" - apiExternalInstanceCreate = "/approval/openapi/v2/external/instance/create" - apiCreate = "/approval/openapi/v2/approval/create" + apiExternalInstanceCreate = "/approval/openapi/v3/external/approval/create" + apiExternalInstanceCheck = "/approval/openapi/v3/external/instance/check" + apiMessageSend = "/approval/openapi/v1/message/send" + apiMessageUpdate = "/approval/openapi/v1/message/update" + apiApprovalCreate = "/approval/openapi/v2/approval/create" apiInstanceCc = "/approval/openapi/v2/instance/cc" apiSubscribe = "/approval/openapi/v2/subscription/subscribe" apiUnsubscribe = "/approval/openapi/v2/subscription/unsubscribe" @@ -60,9 +68,9 @@ func Get(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiGet, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiGet, bytes.NewReader(payload), header) } /* @@ -87,9 +95,9 @@ func InstanceList(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiInstanceList, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiInstanceList, bytes.NewReader(payload), header) } /* @@ -111,9 +119,9 @@ func InstanceGet(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiInstanceGet, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiInstanceGet, bytes.NewReader(payload), header) } /* @@ -135,9 +143,9 @@ func InstanceCreate(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiInstanceCreate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiInstanceCreate, bytes.NewReader(payload), header) } /* @@ -162,9 +170,9 @@ func Approve(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiApprove, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiApprove, bytes.NewReader(payload), header) } /* @@ -188,9 +196,9 @@ func Reject(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiReject, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiReject, bytes.NewReader(payload), header) } /* @@ -214,9 +222,9 @@ func Transfer(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiTransfer, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiTransfer, bytes.NewReader(payload), header) } /* @@ -240,9 +248,9 @@ func Cancel(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiCancel, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiCancel, bytes.NewReader(payload), header) } /* @@ -258,7 +266,39 @@ See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUDOyUjL1gjM14SN4ITN POST https://www.feishu.cn/approval/openapi/v2/file/upload */ -func Upload(ctx *feishu.App, payload []byte) (resp []byte, err error) { +func Upload(ctx *feishu.App, content string, params url.Values) (resp []byte, err error) { + + r, w := io.Pipe() + m := multipart.NewWriter(w) + go func() { + defer w.Close() + defer m.Close() + + part, err := m.CreateFormFile("content", path.Base(content)) + if err != nil { + return + } + file, err := os.Open(content) + if err != nil { + return + } + defer file.Close() + if _, err = io.Copy(part, file); err != nil { + return + } + + // field + err = m.WriteField("type", params.Get("type")) + if err != nil { + return + } + + err = m.WriteField("name", path.Base(content)) + if err != nil { + return + } + + }() accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -266,28 +306,94 @@ func Upload(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", m.FormDataContentType()) - return ctx.Client.HTTPPost(apiUpload, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiUpload, r, header) } /* -三方审批实例同步 +三方审批定义创建/同步 +企业通过第三方审批定义创建接口,帮助企业创建审批定义,创建审批定义后,可以将该审批定义下的审批实例推送到飞书审批应用。 -用于第三方审批的实例同步。 -使用前需确保已经在审批后台创建第三方审批。 -> 审批实例:员工发起审批时产生的对象,详情参见 [开发指南](/ssl:ttdoc/ugTM5UjL4ETO14COxkTN/ukDNyUjL5QjM14SO0ITN) -> +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIDNyYjLyQjM24iM0IjN + +POST https://www.feishu.cn/approval/openapi/v3/external/approval/create +*/ +func ExternalInstanceCreate(ctx *feishu.App, payload []byte) (resp []byte, err error) { + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiExternalInstanceCreate, bytes.NewReader(payload), header) +} + +/* +三方审批实例校验 + +校验三方审批实例数据,用于判断服务端数据是否为最新的。用户提交实例最新更新时间,如果服务端不存在该实例,或者服务端实例更新时间不是最新的,则返回对应实例 id。 + +例如,用户可以每隔5分钟,将最近5分钟产生的实例使用该接口进行对比。 **权限说明** :需要获取 访问审批应用 权限。 -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uczM3UjL3MzN14yNzcTN +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUDNyYjL1QjM24SN0IjN -POST https://www.feishu.cn/approval/openapi/v2/external/instance/create +POST https://www.feishu.cn/approval/openapi/v3/external/instance/check */ -func ExternalInstanceCreate(ctx *feishu.App, payload []byte) (resp []byte, err error) { +func ExternalInstanceCheck(ctx *feishu.App, payload []byte) (resp []byte, err error) { + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiExternalInstanceCheck, bytes.NewReader(payload), header) +} + +/* +发送审批Bot消息 + +此接口可以用来通过飞书审批的Bot推送消息给用户,当有新的审批待办,或者审批待办的状态有更新时,可以通过飞书审批的Bot告知用户。当然开发者也可以利用开放平台的能力自建一个全新的Bot,用来推送审批相关信息。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDNyYjL4QjM24CO0IjN + +POST https://www.feishu.cn/approval/openapi/v1/message/send +*/ +func MessageSend(ctx *feishu.App, payload []byte) (resp []byte, err error) { + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiMessageSend, bytes.NewReader(payload), header) +} + +/* +更新审批Bot消息 + +此接口可以根据审批bot消息id及相应状态,更新相应的审批bot消息。例如,给用户推送了审批待办消息,当用户处理该消息后,可以将之前推送的Bot消息更新为已审批。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNyYjLwYjM24CM2IjN + +POST https://www.feishu.cn/approval/openapi/v1/message/update +*/ +func MessageUpdate(ctx *feishu.App, payload []byte) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -295,9 +401,9 @@ func ExternalInstanceCreate(ctx *feishu.App, payload []byte) (resp []byte, err e } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiExternalInstanceCreate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiMessageUpdate, bytes.NewReader(payload), header) } /* @@ -313,7 +419,7 @@ See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUzNyYjL1cjM24SN3IjN POST https://www.feishu.cn/approval/openapi/v2/approval/create */ -func Create(ctx *feishu.App, payload []byte) (resp []byte, err error) { +func ApprovalCreate(ctx *feishu.App, payload []byte) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -321,9 +427,9 @@ func Create(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiCreate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiApprovalCreate, bytes.NewReader(payload), header) } /* @@ -347,9 +453,9 @@ func InstanceCc(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiInstanceCc, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiInstanceCc, bytes.NewReader(payload), header) } /* @@ -371,9 +477,9 @@ func Subscribe(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiSubscribe, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiSubscribe, bytes.NewReader(payload), header) } /* @@ -395,7 +501,7 @@ func Unsubscribe(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiUnsubscribe, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiUnsubscribe, bytes.NewReader(payload), header) } diff --git a/apis/capabilities/approve/approve_test.go b/apis/capabilities/approval/approval_test.go similarity index 76% rename from apis/capabilities/approve/approve_test.go rename to apis/capabilities/approval/approval_test.go index 4975edf..a121334 100644 --- a/apis/capabilities/approve/approve_test.go +++ b/apis/capabilities/approval/approval_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package approve +package approval import ( "net/http" @@ -34,9 +34,9 @@ func TestGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -70,9 +70,9 @@ func TestInstanceList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiInstanceList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiInstanceList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -106,9 +106,9 @@ func TestInstanceGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiInstanceGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiInstanceGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -142,9 +142,9 @@ func TestInstanceCreate(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiInstanceCreate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiInstanceCreate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -178,9 +178,9 @@ func TestApprove(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiApprove, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiApprove, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -214,9 +214,9 @@ func TestReject(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiReject, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiReject, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -250,9 +250,9 @@ func TestTransfer(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiTransfer, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiTransfer, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -286,9 +286,9 @@ func TestCancel(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiCancel, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiCancel, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -317,14 +317,14 @@ func TestCancel(t *testing.T) { }) } } -func TestUpload(t *testing.T) { +func TestExternalInstanceCreate(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiUpload, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiExternalInstanceCreate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -341,26 +341,26 @@ func TestUpload(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := Upload(tt.args.ctx, tt.args.payload) + gotResp, err := ExternalInstanceCreate(tt.args.ctx, tt.args.payload) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("Upload() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ExternalInstanceCreate() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("Upload() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("ExternalInstanceCreate() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } } -func TestExternalInstanceCreate(t *testing.T) { +func TestExternalInstanceCheck(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiExternalInstanceCreate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiExternalInstanceCheck, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -377,26 +377,98 @@ func TestExternalInstanceCreate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := ExternalInstanceCreate(tt.args.ctx, tt.args.payload) + gotResp, err := ExternalInstanceCheck(tt.args.ctx, tt.args.payload) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("ExternalInstanceCreate() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ExternalInstanceCheck() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("ExternalInstanceCreate() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("ExternalInstanceCheck() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMessageSend(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMessageSend, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MessageSend(tt.args.ctx, tt.args.payload) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MessageSend() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MessageSend() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMessageUpdate(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMessageUpdate, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MessageUpdate(tt.args.ctx, tt.args.payload) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MessageUpdate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MessageUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } } -func TestCreate(t *testing.T) { +func TestApprovalCreate(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiCreate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiApprovalCreate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -413,14 +485,14 @@ func TestCreate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := Create(tt.args.ctx, tt.args.payload) + gotResp, err := ApprovalCreate(tt.args.ctx, tt.args.payload) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("Create() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ApprovalCreate() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("Create() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("ApprovalCreate() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } @@ -430,9 +502,9 @@ func TestInstanceCc(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiInstanceCc, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiInstanceCc, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -466,9 +538,9 @@ func TestSubscribe(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiSubscribe, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiSubscribe, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -502,9 +574,9 @@ func TestUnsubscribe(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiUnsubscribe, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiUnsubscribe, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App diff --git a/apis/capabilities/approve/example_approve_test.go b/apis/capabilities/approval/example_approval_test.go similarity index 63% rename from apis/capabilities/approve/example_approve_test.go rename to apis/capabilities/approval/example_approval_test.go index ed5ee9c..896a2d1 100644 --- a/apis/capabilities/approve/example_approve_test.go +++ b/apis/capabilities/approval/example_approval_test.go @@ -12,21 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package approve_test +package approval_test import ( "fmt" "github.com/fastwego/feishu" - "github.com/fastwego/feishu/apis/capabilities/approve" + "github.com/fastwego/feishu/apis/capabilities/approval" ) func ExampleGet() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.Get(ctx, payload) + resp, err := approval.Get(ctx, payload) fmt.Println(resp, err) } @@ -35,8 +34,7 @@ func ExampleInstanceList() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.InstanceList(ctx, payload) + resp, err := approval.InstanceList(ctx, payload) fmt.Println(resp, err) } @@ -45,8 +43,7 @@ func ExampleInstanceGet() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.InstanceGet(ctx, payload) + resp, err := approval.InstanceGet(ctx, payload) fmt.Println(resp, err) } @@ -55,8 +52,7 @@ func ExampleInstanceCreate() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.InstanceCreate(ctx, payload) + resp, err := approval.InstanceCreate(ctx, payload) fmt.Println(resp, err) } @@ -65,8 +61,7 @@ func ExampleApprove() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.Approve(ctx, payload) + resp, err := approval.Approve(ctx, payload) fmt.Println(resp, err) } @@ -75,8 +70,7 @@ func ExampleReject() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.Reject(ctx, payload) + resp, err := approval.Reject(ctx, payload) fmt.Println(resp, err) } @@ -85,8 +79,7 @@ func ExampleTransfer() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.Transfer(ctx, payload) + resp, err := approval.Transfer(ctx, payload) fmt.Println(resp, err) } @@ -95,38 +88,52 @@ func ExampleCancel() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.Cancel(ctx, payload) + resp, err := approval.Cancel(ctx, payload) fmt.Println(resp, err) } -func ExampleUpload() { +func ExampleExternalInstanceCreate() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.Upload(ctx, payload) + resp, err := approval.ExternalInstanceCreate(ctx, payload) fmt.Println(resp, err) } -func ExampleExternalInstanceCreate() { +func ExampleExternalInstanceCheck() { var ctx *feishu.App payload := []byte("{}") + resp, err := approval.ExternalInstanceCheck(ctx, payload) + + fmt.Println(resp, err) +} + +func ExampleMessageSend() { + var ctx *feishu.App - resp, err := approve.ExternalInstanceCreate(ctx, payload) + payload := []byte("{}") + resp, err := approval.MessageSend(ctx, payload) fmt.Println(resp, err) } -func ExampleCreate() { +func ExampleMessageUpdate() { var ctx *feishu.App payload := []byte("{}") + resp, err := approval.MessageUpdate(ctx, payload) - resp, err := approve.Create(ctx, payload) + fmt.Println(resp, err) +} + +func ExampleApprovalCreate() { + var ctx *feishu.App + + payload := []byte("{}") + resp, err := approval.ApprovalCreate(ctx, payload) fmt.Println(resp, err) } @@ -135,8 +142,7 @@ func ExampleInstanceCc() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.InstanceCc(ctx, payload) + resp, err := approval.InstanceCc(ctx, payload) fmt.Println(resp, err) } @@ -145,8 +151,7 @@ func ExampleSubscribe() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.Subscribe(ctx, payload) + resp, err := approval.Subscribe(ctx, payload) fmt.Println(resp, err) } @@ -155,8 +160,7 @@ func ExampleUnsubscribe() { var ctx *feishu.App payload := []byte("{}") - - resp, err := approve.Unsubscribe(ctx, payload) + resp, err := approval.Unsubscribe(ctx, payload) fmt.Println(resp, err) } diff --git a/apis/capabilities/calendar/calendar.go b/apis/capabilities/calendar/calendar.go index cea5645..4141e15 100644 --- a/apis/capabilities/calendar/calendar.go +++ b/apis/capabilities/calendar/calendar.go @@ -29,11 +29,16 @@ const ( apiCalendarList = "/open-apis/calendar/v3/calendar_list" apiCreateCalendars = "/open-apis/calendar/v3/calendars" apiDeleteCalendarById = "/open-apis/calendar/v3/calendars/:calendarId" + apiUpdateCalendarById = "/open-apis/calendar/v3/calendars/:calendarId" apiGetEventById = "/open-apis/calendar/v3/calendars/:calendarId/events/:eventId" apiCreateEvent = "/open-apis/calendar/v3/calendars/:calendarId/events" + apiGetEvents = "/open-apis/calendar/v3/calendars/:calendarId/events" + apiDeleteEventById = "/open-apis/calendar/v3/calendars/:calendarId/events/:eventId" + apiUpdateEventById = "/open-apis/calendar/v3/calendars/:calendarId/events/:eventId" apiAttendees = "/open-apis/calendar/v3/calendars/:calendarId/events/:eventId/attendees" - apiAcl = "/open-apis/calendar/v3/calendars/:calendarId/acl" - apiDeleteAclByRuleId = "/open-apis/calendar/v3/calendars/:calendarId/acl/:ruleId" + apiGetAcl = "/open-apis/calendar/v3/calendars/:calendarId/acl" + apiCreateAcl = "/open-apis/calendar/v3/calendars/:calendarId/acl" + apiDeleteAcl = "/open-apis/calendar/v3/calendars/:calendarId/acl/:ruleId" apiFreeBusyQuery = "/open-apis/calendar/v3/freebusy/query" apiSharedCalendarQuery = "/open-apis/calendar/v3/shared_calendar_list/shared_calendar/query" apiSharedCalendarEvents = "/open-apis/calendar/v3/shared/calendars/:calendarId/events" @@ -63,9 +68,9 @@ func GetCalendarById(ctx *feishu.App, params url.Values) (resp []byte, err error } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(api, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) } /* @@ -79,7 +84,7 @@ See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMTM14yMxUjLzETN GET https://open.feishu.cn/open-apis/calendar/v3/calendar_list */ -func CalendarList(ctx *feishu.App) (resp []byte, err error) { +func CalendarList(ctx *feishu.App, params url.Values) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -87,9 +92,9 @@ func CalendarList(ctx *feishu.App) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiCalendarList, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiCalendarList+"?"+params.Encode(), header) } /* @@ -111,9 +116,9 @@ func CreateCalendars(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiCreateCalendars, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiCreateCalendars, bytes.NewReader(payload), header) } /* @@ -140,9 +145,38 @@ func DeleteCalendarById(ctx *feishu.App, params url.Values) (resp []byte, err er } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPDelete(api, header) + return ctx.Client.HTTPDelete(feishu.FeishuServerUrl+api, header) +} + +/* +更新日历 + + +该接口用于修改指定日历的信息。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTM14iNxUjL2ETN + +PATCH https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId +*/ +func UpdateCalendarById(ctx *feishu.App, payload []byte, params url.Values) (resp []byte, err error) { + + api := apiUpdateCalendarById + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPatch(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) } /* @@ -169,9 +203,9 @@ func GetEventById(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(api, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) } /* @@ -198,9 +232,96 @@ func CreateEvent(ctx *feishu.App, payload []byte, params url.Values) (resp []byt } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +获取日程列表 + + +该接口用于获取指定日历下的日程列表。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTM14SOxUjL5ETN + +GET https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/events +*/ +func GetEvents(ctx *feishu.App, params url.Values) (resp []byte, err error) { + + api := apiGetEvents + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api+"?"+params.Encode(), header) +} + +/* +删除日程 + + +该接口用于删除指定日历下的日程。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjM14CMyUjLwITN + +DELETE https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/events/:eventId +*/ +func DeleteEventById(ctx *feishu.App, params url.Values) (resp []byte, err error) { + + api := apiDeleteEventById + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPDelete(feishu.FeishuServerUrl+api, header) +} + +/* +更新日程 + + +该接口用于更新日程信息。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjM14SMyUjLxITN + +PATCH https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/events/:eventId +*/ +func UpdateEventById(ctx *feishu.App, payload []byte, params url.Values) (resp []byte, err error) { + + api := apiUpdateEventById + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPatch(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) } /* @@ -228,9 +349,9 @@ func Attendees(ctx *feishu.App, payload []byte, params url.Values) (resp []byte, } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) } /* @@ -244,9 +365,38 @@ See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjM14yMyUjLzITN GET https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/acl */ -func Acl(ctx *feishu.App, params url.Values) (resp []byte, err error) { +func GetAcl(ctx *feishu.App, params url.Values) (resp []byte, err error) { + + api := apiGetAcl + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) +} + +/* +创建访问控制 + + +该接口用于邀请一个用户加入日历。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQjM14CNyUjL0ITN + +POST https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/acl +*/ +func CreateAcl(ctx *feishu.App, payload []byte, params url.Values) (resp []byte, err error) { - api := apiAcl + api := apiCreateAcl for paramName, paramValues := range params { api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) } @@ -257,9 +407,9 @@ func Acl(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(api, header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) } /* @@ -273,9 +423,9 @@ See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUjM14SNyUjL1ITN DELETE https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/acl/:ruleId */ -func DeleteAclByRuleId(ctx *feishu.App, params url.Values) (resp []byte, err error) { +func DeleteAcl(ctx *feishu.App, params url.Values) (resp []byte, err error) { - api := apiDeleteAclByRuleId + api := apiDeleteAcl for paramName, paramValues := range params { api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) } @@ -286,9 +436,9 @@ func DeleteAclByRuleId(ctx *feishu.App, params url.Values) (resp []byte, err err } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPDelete(api, header) + return ctx.Client.HTTPDelete(feishu.FeishuServerUrl+api, header) } /* @@ -310,9 +460,9 @@ func FreeBusyQuery(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiFreeBusyQuery, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiFreeBusyQuery, bytes.NewReader(payload), header) } /* @@ -334,9 +484,9 @@ func SharedCalendarQuery(ctx *feishu.App, params url.Values) (resp []byte, err e } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiSharedCalendarQuery+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiSharedCalendarQuery+"?"+params.Encode(), header) } /* @@ -363,7 +513,7 @@ func SharedCalendarEvents(ctx *feishu.App, params url.Values) (resp []byte, err } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(api, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) } diff --git a/apis/capabilities/calendar/calendar_test.go b/apis/capabilities/calendar/calendar_test.go index 8233168..7fb38a4 100644 --- a/apis/capabilities/calendar/calendar_test.go +++ b/apis/capabilities/calendar/calendar_test.go @@ -35,9 +35,9 @@ func TestGetCalendarById(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiGetCalendarById, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiGetCalendarById, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -72,12 +72,14 @@ func TestCalendarList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiCalendarList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiCalendarList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App + + params url.Values } tests := []struct { name string @@ -90,7 +92,7 @@ func TestCalendarList(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := CalendarList(tt.args.ctx) + gotResp, err := CalendarList(tt.args.ctx, tt.args.params) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { t.Errorf("CalendarList() error = %v, wantErr %v", err, tt.wantErr) @@ -107,9 +109,9 @@ func TestCreateCalendars(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiCreateCalendars, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiCreateCalendars, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -143,9 +145,9 @@ func TestDeleteCalendarById(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDeleteCalendarById, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDeleteCalendarById, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("DELETE") type args struct { ctx *feishu.App @@ -175,14 +177,52 @@ func TestDeleteCalendarById(t *testing.T) { }) } } +func TestUpdateCalendarById(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiUpdateCalendarById, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("PATCH") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := UpdateCalendarById(tt.args.ctx, tt.args.payload, tt.args.params) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("UpdateCalendarById() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("UpdateCalendarById() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} func TestGetEventById(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiGetEventById, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiGetEventById, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -217,9 +257,9 @@ func TestCreateEvent(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiCreateEvent, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiCreateEvent, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -250,14 +290,126 @@ func TestCreateEvent(t *testing.T) { }) } } +func TestGetEvents(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiGetEvents, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := GetEvents(tt.args.ctx, tt.args.params) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("GetEvents() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("GetEvents() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestDeleteEventById(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiDeleteEventById, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("DELETE") + + type args struct { + ctx *feishu.App + + params url.Values + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := DeleteEventById(tt.args.ctx, tt.args.params) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("DeleteEventById() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("DeleteEventById() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestUpdateEventById(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiUpdateEventById, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("PATCH") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := UpdateEventById(tt.args.ctx, tt.args.payload, tt.args.params) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("UpdateEventById() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("UpdateEventById() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} func TestAttendees(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAttendees, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAttendees, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -288,14 +440,14 @@ func TestAttendees(t *testing.T) { }) } } -func TestAcl(t *testing.T) { +func TestGetAcl(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAcl, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiGetAcl, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -313,26 +465,64 @@ func TestAcl(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := Acl(tt.args.ctx, tt.args.params) + gotResp, err := GetAcl(tt.args.ctx, tt.args.params) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("GetAcl() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("GetAcl() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestCreateAcl(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiCreateAcl, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := CreateAcl(tt.args.ctx, tt.args.payload, tt.args.params) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("Acl() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("CreateAcl() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("Acl() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("CreateAcl() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } } -func TestDeleteAclByRuleId(t *testing.T) { +func TestDeleteAcl(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDeleteAclByRuleId, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDeleteAcl, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("DELETE") type args struct { ctx *feishu.App @@ -350,14 +540,14 @@ func TestDeleteAclByRuleId(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := DeleteAclByRuleId(tt.args.ctx, tt.args.params) + gotResp, err := DeleteAcl(tt.args.ctx, tt.args.params) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("DeleteAclByRuleId() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("DeleteAcl() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DeleteAclByRuleId() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("DeleteAcl() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } @@ -367,9 +557,9 @@ func TestFreeBusyQuery(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiFreeBusyQuery, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiFreeBusyQuery, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -403,9 +593,9 @@ func TestSharedCalendarQuery(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiSharedCalendarQuery, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiSharedCalendarQuery, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -440,9 +630,9 @@ func TestSharedCalendarEvents(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiSharedCalendarEvents, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiSharedCalendarEvents, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App diff --git a/apis/capabilities/calendar/example_calendar_test.go b/apis/capabilities/calendar/example_calendar_test.go index 1e55e3e..8427c02 100644 --- a/apis/capabilities/calendar/example_calendar_test.go +++ b/apis/capabilities/calendar/example_calendar_test.go @@ -26,7 +26,6 @@ func ExampleGetCalendarById() { var ctx *feishu.App params := url.Values{} - resp, err := calendar.GetCalendarById(ctx, params) fmt.Println(resp, err) @@ -35,7 +34,8 @@ func ExampleGetCalendarById() { func ExampleCalendarList() { var ctx *feishu.App - resp, err := calendar.CalendarList(ctx) + params := url.Values{} + resp, err := calendar.CalendarList(ctx, params) fmt.Println(resp, err) } @@ -44,7 +44,6 @@ func ExampleCreateCalendars() { var ctx *feishu.App payload := []byte("{}") - resp, err := calendar.CreateCalendars(ctx, payload) fmt.Println(resp, err) @@ -54,17 +53,25 @@ func ExampleDeleteCalendarById() { var ctx *feishu.App params := url.Values{} - resp, err := calendar.DeleteCalendarById(ctx, params) fmt.Println(resp, err) } -func ExampleGetEventById() { +func ExampleUpdateCalendarById() { var ctx *feishu.App + payload := []byte("{}") params := url.Values{} + resp, err := calendar.UpdateCalendarById(ctx, payload, params) + + fmt.Println(resp, err) +} + +func ExampleGetEventById() { + var ctx *feishu.App + params := url.Values{} resp, err := calendar.GetEventById(ctx, params) fmt.Println(resp, err) @@ -75,39 +82,73 @@ func ExampleCreateEvent() { payload := []byte("{}") params := url.Values{} - resp, err := calendar.CreateEvent(ctx, payload, params) fmt.Println(resp, err) } -func ExampleAttendees() { +func ExampleGetEvents() { + var ctx *feishu.App + + params := url.Values{} + resp, err := calendar.GetEvents(ctx, params) + + fmt.Println(resp, err) +} + +func ExampleDeleteEventById() { + var ctx *feishu.App + + params := url.Values{} + resp, err := calendar.DeleteEventById(ctx, params) + + fmt.Println(resp, err) +} + +func ExampleUpdateEventById() { var ctx *feishu.App payload := []byte("{}") params := url.Values{} + resp, err := calendar.UpdateEventById(ctx, payload, params) + + fmt.Println(resp, err) +} + +func ExampleAttendees() { + var ctx *feishu.App + payload := []byte("{}") + params := url.Values{} resp, err := calendar.Attendees(ctx, payload, params) fmt.Println(resp, err) } -func ExampleAcl() { +func ExampleGetAcl() { var ctx *feishu.App params := url.Values{} - - resp, err := calendar.Acl(ctx, params) + resp, err := calendar.GetAcl(ctx, params) fmt.Println(resp, err) } -func ExampleDeleteAclByRuleId() { +func ExampleCreateAcl() { var ctx *feishu.App + payload := []byte("{}") params := url.Values{} + resp, err := calendar.CreateAcl(ctx, payload, params) + + fmt.Println(resp, err) +} - resp, err := calendar.DeleteAclByRuleId(ctx, params) +func ExampleDeleteAcl() { + var ctx *feishu.App + + params := url.Values{} + resp, err := calendar.DeleteAcl(ctx, params) fmt.Println(resp, err) } @@ -116,7 +157,6 @@ func ExampleFreeBusyQuery() { var ctx *feishu.App payload := []byte("{}") - resp, err := calendar.FreeBusyQuery(ctx, payload) fmt.Println(resp, err) @@ -126,7 +166,6 @@ func ExampleSharedCalendarQuery() { var ctx *feishu.App params := url.Values{} - resp, err := calendar.SharedCalendarQuery(ctx, params) fmt.Println(resp, err) @@ -136,7 +175,6 @@ func ExampleSharedCalendarEvents() { var ctx *feishu.App params := url.Values{} - resp, err := calendar.SharedCalendarEvents(ctx, params) fmt.Println(resp, err) diff --git a/apis/capabilities/document/comment/comment.go b/apis/capabilities/document/comment/comment.go new file mode 100644 index 0000000..d038207 --- /dev/null +++ b/apis/capabilities/document/comment/comment.go @@ -0,0 +1,34 @@ +// Package comment 云文档/评论 +package comment + +import ( + "bytes" + "net/http" + + "github.com/fastwego/feishu" +) + +const ( + apiAddWhole = "/open-apis/comment/add_whole" +) + +/* +添加全文评论 + + + +该接口用于根据 filetoken 给文档添加全文评论 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucDN4UjL3QDO14yN0gTN + +POST https://open.feishu.cn/open-apis/comment/add_whole +*/ +func AddWhole(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiAddWhole, bytes.NewReader(payload), header) +} diff --git a/apis/capabilities/document/comment/comment_test.go b/apis/capabilities/document/comment/comment_test.go new file mode 100644 index 0000000..73f621f --- /dev/null +++ b/apis/capabilities/document/comment/comment_test.go @@ -0,0 +1,54 @@ +package comment + +import ( + "net/http" + "os" + "reflect" + "testing" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/test" +) + +func TestMain(m *testing.M) { + test.Setup() + os.Exit(m.Run()) +} + +func TestAddWhole(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiAddWhole, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := AddWhole(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("AddWhole() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("AddWhole() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} diff --git a/apis/capabilities/document/comment/example_comment_test.go b/apis/capabilities/document/comment/example_comment_test.go new file mode 100644 index 0000000..606364c --- /dev/null +++ b/apis/capabilities/document/comment/example_comment_test.go @@ -0,0 +1,18 @@ +package comment_test + +import ( + "fmt" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/apis/capabilities/document/comment" +) + +func ExampleAddWhole() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := comment.AddWhole(ctx, payload, accessToken) + + fmt.Println(resp, err) +} diff --git a/apis/capabilities/document/docs/docs.go b/apis/capabilities/document/docs/docs.go new file mode 100644 index 0000000..a420225 --- /dev/null +++ b/apis/capabilities/document/docs/docs.go @@ -0,0 +1,90 @@ +// Package docs 云文档/docs +package docs + +import ( + "net/http" + "net/url" + "strings" + + "github.com/fastwego/feishu" +) + +const ( + apiRawContent = "/open-apis/doc/v2/:docToken/raw_content" + apiSheetMeta = "/open-apis/doc/v2/:docToken/sheet_meta" + apiDocMeta = "/open-apis/doc/v2/meta/:docToken" +) + +/* +获取文档文本内容 + + +该接口用于获取文档的纯文本内容,不包含富文本格式信息,主要用于搜索,如导入 es 等。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukzNzUjL5czM14SO3MTN + +GET https://open.feishu.cn/open-apis/doc/v2/:docToken/raw_content +*/ +func RawContent(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiRawContent + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) +} + +/* +获取sheet@doc的元数据 + +该接口用于根据 docToken 获取 sheet@doc 的元数据。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uADOzUjLwgzM14CM4MTN + +GET https://open.feishu.cn/open-apis/doc/v2/:docToken/sheet_meta +*/ +func SheetMeta(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiSheetMeta + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) +} + +/* +获取文档元信息 + + +该接口用于根据 docToken 获取元数据。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uczN3UjL3czN14yN3cTN + +GET https://open.feishu.cn/open-apis/doc/v2/meta/:docToken +*/ +func DocMeta(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiDocMeta + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) +} diff --git a/apis/capabilities/document/docs/docs_test.go b/apis/capabilities/document/docs/docs_test.go new file mode 100644 index 0000000..4c100ec --- /dev/null +++ b/apis/capabilities/document/docs/docs_test.go @@ -0,0 +1,132 @@ +package docs + +import ( + "net/http" + "net/url" + "os" + "reflect" + "testing" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/test" +) + +func TestMain(m *testing.M) { + test.Setup() + os.Exit(m.Run()) +} + +func TestRawContent(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiRawContent, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := RawContent(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("RawContent() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("RawContent() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestSheetMeta(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiSheetMeta, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := SheetMeta(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("SheetMeta() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("SheetMeta() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestDocMeta(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiDocMeta, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := DocMeta(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("DocMeta() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("DocMeta() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} diff --git a/apis/capabilities/document/docs/example_docs_test.go b/apis/capabilities/document/docs/example_docs_test.go new file mode 100644 index 0000000..19bc080 --- /dev/null +++ b/apis/capabilities/document/docs/example_docs_test.go @@ -0,0 +1,39 @@ +package docs_test + +import ( + "fmt" + "net/url" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/apis/capabilities/document/docs" +) + +func ExampleRawContent() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := docs.RawContent(ctx, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleSheetMeta() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := docs.SheetMeta(ctx, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleDocMeta() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := docs.DocMeta(ctx, params, accessToken) + + fmt.Println(resp, err) +} diff --git a/apis/capabilities/document/document.go b/apis/capabilities/document/document.go deleted file mode 100644 index 57eea33..0000000 --- a/apis/capabilities/document/document.go +++ /dev/null @@ -1,749 +0,0 @@ -// Copyright 2020 FastWeGo -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package document 云文档 -package document - -import ( - "bytes" - "net/http" - "net/url" - "strings" - - "github.com/fastwego/feishu" -) - -const ( - apiCreateFolder = "/open-apis/drive/explorer/v2/folder/:folderToken" - apiRootFolderMeta = "/open-apis/drive/explorer/v2/root_folder/meta" - apiFolderChildren = "/open-apis/drive/explorer/v2/folder/:folderToken/children" - apiCreateFile = "/open-apis/drive/explorer/v2/file/:folderToken" - apiCopyFile = "/open-apis/drive/explorer/v2/file/copy/files/:fileToken" - apiDeleteFile = "/open-apis/drive/explorer/v2/file/spreadsheets/:spreadsheetToken" - apiPermissionMemberCreate = "/open-apis/drive/permission/member/create" - apiPermissionMemberTransfer = "/open-apis/drive/permission/member/transfer" - apiPermissionPublicUpdate = "/open-apis/drive/permission/public/update" - apiPermissionMemberList = "/open-apis/drive/permission/member/list" - apiPermissionMemberDelete = "/open-apis/drive/permission/member/delete" - apiPermissionMemberUpdate = "/open-apis/drive/permission/member/update" - apiPermissionMemberPermitted = "/open-apis/drive/permission/member/permitted" - apiRawContent = "/open-apis/doc/v2/:docToken/raw_content" - apiSheetMeta = "/open-apis/doc/v2/:docToken/sheet_meta" - apiDocMeta = "/open-apis/doc/v2/meta/:docToken" - apiSpreadSheetsMetainfo = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/metainfo" - apiSheetsBatchUpdate = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/sheets_batch_update" - apiSpreadSheetsValuesPrepend = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_prepend" - apiSpreadSheetsValuesAppend = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_append" - apiSpreadSheetsInsertDimensionRange = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/insert_dimension_range" - apiSpreadSheetsDimensionRange = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range" - apiSpreadSheetsProtectedDimension = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/protected_dimension" - apiSpreadSheetsMergeCells = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/merge_cells" - apiSpreadSheetsUnmergeCells = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/unmerge_cells" - apiSpreadSheetsRange = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values/:range" - apiSpreadSheetsValuesBatchGet = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_get" - apiSpreadSheetsValuesBatchUpdate = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_update" - apiDocsMeta = "/open-apis/suite/docs-api/meta" - apiSearchObject = "/open-apis/suite/docs-api/search/object" - apiCommentAddWhole = "/open-apis/comment/add_whole" -) - -/* -新建文件夹 - - - -该接口用于根据 folderToken 在该 folder 下创建文件夹 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTNzUjL5UzM14SO1MTN - -POST https://open.feishu.cn/open-apis/drive/explorer/v2/folder/:folderToken -*/ -func CreateFolder(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiCreateFolder - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -获取文件夹元信息 - - -# 获取root folder(我的空间) meta该接口用于获取 我的空间 的元信息 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNzUjLwYzM14CM2MTN - -GET https://open.feishu.cn/open-apis/drive/explorer/v2/root_folder/meta -*/ -func RootFolderMeta(ctx *feishu.App, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPGet(apiRootFolderMeta, header) -} - -/* -获取文件夹下的文档清单 - - - -该接口用于根据 folderToken 获取该文件夹的文档清单,如 doc、sheet、folder - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjNzUjLxYzM14SM2MTN - -GET https://open.feishu.cn/open-apis/drive/explorer/v2/folder/:folderToken/children -*/ -func FolderChildren(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiFolderChildren - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPGet(api, header) -} - -/* -新建文档 - - -该接口用于根据 folderToken 创建 Doc或 Sheet 。 - -若没有特定的文件夹用于承载创建的文档,可以先调用「获取文件夹元信息」文档中的「获取 root folder (我的空间) meta」接口,获得我的空间的 token,然后再使用此接口。创建的文档将会在「我的空间」的「归我所有」列表里。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQTNzUjL0UzM14CN1MTN - -POST https://open.feishu.cn/open-apis/drive/explorer/v2/file/:folderToken -*/ -func CreateFile(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiCreateFile - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -复制文档 - - - -该接口用于根据文件 token 复制 Doc 或 Sheet 到目标文件夹中。 - -若没有特定的文件夹用于承载创建的文档,可以先调用「获取文件夹元信息」文档中的「获取 root folder (我的空间) meta」接口,获得我的空间的 token,然后再使用此接口。复制的文档将会在「我的空间」的「归我所有」列表里。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTNzUjL2UzM14iN1MTN - -POST https://open.feishu.cn/open-apis/drive/explorer/v2/file/copy/files/:fileToken -*/ -func CopyFile(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiCopyFile - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -删除文档 - -Doc - -该接口用于根据 spreadsheetToken 删除对应的 sheet 文档。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATM2UjLwEjN14CMxYTN - -DELETE https://open.feishu.cn/open-apis/drive/explorer/v2/file/spreadsheets/:spreadsheetToken -*/ -func DeleteFile(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiDeleteFile - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPDelete(api, header) -} - -/* -增加权限 - - - -该接口用于根据 filetoken 给用户增加文档的权限 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMzNzUjLzczM14yM3MTN - -POST https://open.feishu.cn/open-apis/drive/permission/member/create -*/ -func PermissionMemberCreate(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiPermissionMemberCreate, bytes.NewReader(payload), header) -} - -/* -转移拥有者 - - - -该接口用于根据文档信息和用户信息转移文档的所有者。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQzNzUjL0czM14CN3MTN - -POST https://open.feishu.cn/open-apis/drive/permission/member/transfer -*/ -func PermissionMemberTransfer(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiPermissionMemberTransfer, bytes.NewReader(payload), header) -} - -/* -更新文档公共设置 - - - -该接口用于根据 filetoken 更新文档的公共设置 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTM3UjL5EzN14SOxcTN - -POST https://open.feishu.cn/open-apis/drive/permission/public/update -*/ -func PermissionPublicUpdate(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiPermissionPublicUpdate, bytes.NewReader(payload), header) -} - -/* -获取协作者列表 - - - -该接口用于根据 filetoken 查询协作者,目前包括人('user')和群('chat') - -**你能获取到协作者列表的前提是你对该文档有权限** - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATN3UjLwUzN14CM1cTN - -POST https://open.feishu.cn/open-apis/drive/permission/member/list -*/ -func PermissionMemberList(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiPermissionMemberList, bytes.NewReader(payload), header) -} - -/* -移除协作者权限 - - - -该接口用于根据 filetoken 移除文档协作者的权限 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTN3UjL2UzN14iN1cTN - -POST https://open.feishu.cn/open-apis/drive/permission/member/delete -*/ -func PermissionMemberDelete(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiPermissionMemberDelete, bytes.NewReader(payload), header) -} - -/* -更新协作者权限 - - - -该接口用于根据 filetoken 更新文档协作者的权限 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucTN3UjL3UzN14yN1cTN - -POST https://open.feishu.cn/open-apis/drive/permission/member/update -*/ -func PermissionMemberUpdate(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiPermissionMemberUpdate, bytes.NewReader(payload), header) -} - -/* -判断协作者是否有某权限 - - - -该接口用于根据 filetoken 判断当前登录用户是否具有某权限 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYzN3UjL2czN14iN3cTN - -POST https://open.feishu.cn/open-apis/drive/permission/member/permitted -*/ -func PermissionMemberPermitted(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiPermissionMemberPermitted, bytes.NewReader(payload), header) -} - -/* -获取文档文本内容 - - -该接口用于获取文档的纯文本内容,不包含富文本格式信息,主要用于搜索,如导入 es 等。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukzNzUjL5czM14SO3MTN - -GET https://open.feishu.cn/open-apis/doc/v2/:docToken/raw_content -*/ -func RawContent(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiRawContent - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPGet(api, header) -} - -/* -获取sheet@doc的元数据 - -sheet@doc 的元数据 - -该接口用于根据 docToken 获取 sheet@doc 的元数据。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uADOzUjLwgzM14CM4MTN - -GET https://open.feishu.cn/open-apis/doc/v2/:docToken/sheet_meta -*/ -func SheetMeta(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSheetMeta - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPGet(api, header) -} - -/* -获取文档元信息 - - -该接口用于根据 docToken 获取元数据。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uczN3UjL3czN14yN3cTN - -GET https://open.feishu.cn/open-apis/doc/v2/meta/:docToken -*/ -func DocMeta(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiDocMeta - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPGet(api, header) -} - -/* -获取表格元数据 - - -该接口用于根据 spreadsheetToken 获取表格元数据。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uETMzUjLxEzM14SMxMTN - -GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/metainfo -*/ -func SpreadSheetsMetainfo(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsMetainfo - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPGet(api, header) -} - -/* -操作子表 - - - -该接口用于根据 spreadsheetToken 操作表格,如增加sheet,复制sheet、删除sheet。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTMzUjL2EzM14iNxMTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/sheets_batch_update -*/ -func SheetsBatchUpdate(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSheetsBatchUpdate - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -插入数据 - - - -该接口用于根据 spreadsheetToken 和 range 向范围之前增加相应数据的行和相应的数据,相当于数组的插入操作;单次写入不超过5000行,100列,每个格子大小为0.5M。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIjMzUjLyIzM14iMyMTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_prepend -*/ -func SpreadSheetsValuesPrepend(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsValuesPrepend - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -追加数据 - - - -该接口用于根据 spreadsheetToken 和 range 遇到空行则进行覆盖追加或新增行追加数据。 空行:默认该行第一个格子是空,则认为是空行;单次写入不超过5000行,100列,每个格子大小为0.5M。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjMzUjLzIzM14yMyMTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_append -*/ -func SpreadSheetsValuesAppend(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsValuesAppend - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -插入行列 - - - -该接口用于根据 spreadsheetToken 和维度信息 插入空行/列 。如 startIndex=3, endIndex=7,则从第 4 行开始开始插入行列,一直到第 7 行,共插入 4 行;单次操作不超过5000行或列。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQjMzUjL0IzM14CNyMTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/insert_dimension_range -*/ -func SpreadSheetsInsertDimensionRange(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsInsertDimensionRange - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -增加行列 - - - -该接口用于根据 spreadsheetToken 和长度,在末尾增加空行/列;单次操作不超过5000行或列。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUjMzUjL1IzM14SNyMTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range -*/ -func SpreadSheetsDimensionRange(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsDimensionRange - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -增加锁定单元格 - - - -该接口用于根据 spreadsheetToken 和维度信息增加多个范围的锁定单元格;单次操作不超过5000行或列。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDNzUjL4QzM14CO0MTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/protected_dimension -*/ -func SpreadSheetsProtectedDimension(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsProtectedDimension - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -合并单元格 - - - -该接口用于根据 spreadsheetToken 和维度信息合并单元格;单次操作不超过5000行,100列。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukDNzUjL5QzM14SO0MTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/merge_cells -*/ -func SpreadSheetsMergeCells(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsMergeCells - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -拆分单元格 - - - -该接口用于根据 spreadsheetToken 和维度信息拆分单元格;单次操作不超过5000行,100列。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATNzUjLwUzM14CM1MTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/unmerge_cells -*/ -func SpreadSheetsUnmergeCells(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsUnmergeCells - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -读取单个范围 - - - -该接口用于根据 spreadsheetToken 和 range 读取表格单个范围的值,返回数据限制为10M。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugTMzUjL4EzM14COxMTN - -GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values/:range -*/ -func SpreadSheetsRange(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsRange - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPGet(api, header) -} - -/* -读取多个范围 - - - -该接口用于根据 spreadsheetToken 和 ranges 读取表格多个范围的值,返回数据限制为10M。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTMzUjL5EzM14SOxMTN - -GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_get -*/ -func SpreadSheetsValuesBatchGet(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsValuesBatchGet - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPGet(api, header) -} - -/* -向多个范围写入数据 - - - -该接口用于根据 spreadsheetToken 和 range 向多个范围写入数据,若范围内有数据,将被更新覆盖;单次写入不超过5000行,100列,每个格子大小为0.5M。 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjMzUjLxIzM14SMyMTN - -POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_update -*/ -func SpreadSheetsValuesBatchUpdate(ctx *feishu.App, payload []byte, params url.Values, header http.Header) (resp []byte, err error) { - - api := apiSpreadSheetsValuesBatchUpdate - for paramName, paramValues := range params { - api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) - } - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(api, bytes.NewReader(payload), header) -} - -/* -获取元数据 - - - -该接口用于根据 token 获取各类文件的元数据 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjN3UjLzYzN14yM2cTN - -POST https://open.feishu.cn/open-apis/suite/docs-api/meta -*/ -func DocsMeta(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiDocsMeta, bytes.NewReader(payload), header) -} - -/* -文档搜索 - - - -该接口用于根据搜索条件进行文档搜索 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDM4UjL4ADO14COwgTN - -POST https://open.feishu.cn/open-apis/suite/docs-api/search/object -*/ -func SearchObject(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiSearchObject, bytes.NewReader(payload), header) -} - -/* -添加全文评论 - - - -该接口用于根据 filetoken 给文档添加全文评论 - - -See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucDN4UjL3QDO14yN0gTN - -POST https://open.feishu.cn/open-apis/comment/add_whole -*/ -func CommentAddWhole(ctx *feishu.App, payload []byte, header http.Header) (resp []byte, err error) { - - header.Set("Content-appType", "application/json") - - return ctx.Client.HTTPPost(apiCommentAddWhole, bytes.NewReader(payload), header) -} diff --git a/apis/capabilities/document/document_test.go b/apis/capabilities/document/document_test.go deleted file mode 100644 index 6d7e228..0000000 --- a/apis/capabilities/document/document_test.go +++ /dev/null @@ -1,1211 +0,0 @@ -// Copyright 2020 FastWeGo -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package document - -import ( - "net/http" - "net/url" - "os" - "reflect" - "testing" - - "github.com/fastwego/feishu" - "github.com/fastwego/feishu/test" -) - -func TestMain(m *testing.M) { - test.Setup() - os.Exit(m.Run()) -} - -func TestCreateFolder(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiCreateFolder, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := CreateFolder(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("CreateFolder() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("CreateFolder() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestRootFolderMeta(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiRootFolderMeta, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := RootFolderMeta(tt.args.ctx, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("RootFolderMeta() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("RootFolderMeta() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestFolderChildren(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiFolderChildren, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := FolderChildren(tt.args.ctx, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("FolderChildren() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("FolderChildren() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestCreateFile(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiCreateFile, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := CreateFile(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("CreateFile() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("CreateFile() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestCopyFile(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiCopyFile, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := CopyFile(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("CopyFile() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("CopyFile() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestDeleteFile(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiDeleteFile, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := DeleteFile(tt.args.ctx, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("DeleteFile() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DeleteFile() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestPermissionMemberCreate(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiPermissionMemberCreate, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := PermissionMemberCreate(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("PermissionMemberCreate() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("PermissionMemberCreate() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestPermissionMemberTransfer(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiPermissionMemberTransfer, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := PermissionMemberTransfer(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("PermissionMemberTransfer() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("PermissionMemberTransfer() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestPermissionPublicUpdate(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiPermissionPublicUpdate, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := PermissionPublicUpdate(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("PermissionPublicUpdate() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("PermissionPublicUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestPermissionMemberList(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiPermissionMemberList, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := PermissionMemberList(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("PermissionMemberList() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("PermissionMemberList() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestPermissionMemberDelete(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiPermissionMemberDelete, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := PermissionMemberDelete(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("PermissionMemberDelete() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("PermissionMemberDelete() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestPermissionMemberUpdate(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiPermissionMemberUpdate, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := PermissionMemberUpdate(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("PermissionMemberUpdate() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("PermissionMemberUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestPermissionMemberPermitted(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiPermissionMemberPermitted, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := PermissionMemberPermitted(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("PermissionMemberPermitted() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("PermissionMemberPermitted() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestRawContent(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiRawContent, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := RawContent(tt.args.ctx, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("RawContent() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("RawContent() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSheetMeta(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSheetMeta, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SheetMeta(tt.args.ctx, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SheetMeta() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SheetMeta() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestDocMeta(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiDocMeta, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := DocMeta(tt.args.ctx, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("DocMeta() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DocMeta() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsMetainfo(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsMetainfo, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsMetainfo(tt.args.ctx, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsMetainfo() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsMetainfo() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSheetsBatchUpdate(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSheetsBatchUpdate, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SheetsBatchUpdate(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SheetsBatchUpdate() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SheetsBatchUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsValuesPrepend(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsValuesPrepend, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsValuesPrepend(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsValuesPrepend() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsValuesPrepend() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsValuesAppend(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsValuesAppend, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsValuesAppend(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsValuesAppend() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsValuesAppend() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsInsertDimensionRange(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsInsertDimensionRange, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsInsertDimensionRange(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsInsertDimensionRange() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsInsertDimensionRange() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsDimensionRange(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsDimensionRange, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsDimensionRange(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsDimensionRange() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsDimensionRange() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsProtectedDimension(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsProtectedDimension, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsProtectedDimension(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsProtectedDimension() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsProtectedDimension() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsMergeCells(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsMergeCells, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsMergeCells(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsMergeCells() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsMergeCells() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsUnmergeCells(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsUnmergeCells, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsUnmergeCells(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsUnmergeCells() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsUnmergeCells() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsRange(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsRange, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsRange(tt.args.ctx, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsRange() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsRange() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsValuesBatchGet(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsValuesBatchGet, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsValuesBatchGet(tt.args.ctx, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsValuesBatchGet() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsValuesBatchGet() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSpreadSheetsValuesBatchUpdate(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSpreadSheetsValuesBatchUpdate, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - - params url.Values - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SpreadSheetsValuesBatchUpdate(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SpreadSheetsValuesBatchUpdate() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SpreadSheetsValuesBatchUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestDocsMeta(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiDocsMeta, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := DocsMeta(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("DocsMeta() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DocsMeta() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestSearchObject(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiSearchObject, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := SearchObject(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("SearchObject() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("SearchObject() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} -func TestCommentAddWhole(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiCommentAddWhole, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - header http.Header - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := CommentAddWhole(tt.args.ctx, tt.args.payload, tt.args.header) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("CommentAddWhole() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("CommentAddWhole() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} diff --git a/apis/capabilities/document/example_document_test.go b/apis/capabilities/document/example_document_test.go deleted file mode 100644 index 1f3f27e..0000000 --- a/apis/capabilities/document/example_document_test.go +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2020 FastWeGo -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package document_test - -import ( - "fmt" - "net/http" - "net/url" - - "github.com/fastwego/feishu" - "github.com/fastwego/feishu/apis/capabilities/document" -) - -func ExampleCreateFolder() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.CreateFolder(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleRootFolderMeta() { - var ctx *feishu.App - - header := http.Header{} - resp, err := document.RootFolderMeta(ctx, header) - - fmt.Println(resp, err) -} - -func ExampleFolderChildren() { - var ctx *feishu.App - - params := url.Values{} - header := http.Header{} - resp, err := document.FolderChildren(ctx, params, header) - - fmt.Println(resp, err) -} - -func ExampleCreateFile() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.CreateFile(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleCopyFile() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.CopyFile(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleDeleteFile() { - var ctx *feishu.App - - params := url.Values{} - header := http.Header{} - resp, err := document.DeleteFile(ctx, params, header) - - fmt.Println(resp, err) -} - -func ExamplePermissionMemberCreate() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.PermissionMemberCreate(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExamplePermissionMemberTransfer() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.PermissionMemberTransfer(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExamplePermissionPublicUpdate() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.PermissionPublicUpdate(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExamplePermissionMemberList() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.PermissionMemberList(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExamplePermissionMemberDelete() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.PermissionMemberDelete(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExamplePermissionMemberUpdate() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.PermissionMemberUpdate(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExamplePermissionMemberPermitted() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.PermissionMemberPermitted(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExampleRawContent() { - var ctx *feishu.App - - params := url.Values{} - header := http.Header{} - resp, err := document.RawContent(ctx, params, header) - - fmt.Println(resp, err) -} - -func ExampleSheetMeta() { - var ctx *feishu.App - - params := url.Values{} - header := http.Header{} - resp, err := document.SheetMeta(ctx, params, header) - - fmt.Println(resp, err) -} - -func ExampleDocMeta() { - var ctx *feishu.App - - params := url.Values{} - header := http.Header{} - resp, err := document.DocMeta(ctx, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsMetainfo() { - var ctx *feishu.App - - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsMetainfo(ctx, params, header) - - fmt.Println(resp, err) -} - -func ExampleSheetsBatchUpdate() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SheetsBatchUpdate(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsValuesPrepend() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsValuesPrepend(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsValuesAppend() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsValuesAppend(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsInsertDimensionRange() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsInsertDimensionRange(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsDimensionRange() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsDimensionRange(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsProtectedDimension() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsProtectedDimension(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsMergeCells() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsMergeCells(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsUnmergeCells() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsUnmergeCells(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsRange() { - var ctx *feishu.App - - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsRange(ctx, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsValuesBatchGet() { - var ctx *feishu.App - - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsValuesBatchGet(ctx, params, header) - - fmt.Println(resp, err) -} - -func ExampleSpreadSheetsValuesBatchUpdate() { - var ctx *feishu.App - - payload := []byte("{}") - params := url.Values{} - header := http.Header{} - resp, err := document.SpreadSheetsValuesBatchUpdate(ctx, payload, params, header) - - fmt.Println(resp, err) -} - -func ExampleDocsMeta() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.DocsMeta(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExampleSearchObject() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.SearchObject(ctx, payload, header) - - fmt.Println(resp, err) -} - -func ExampleCommentAddWhole() { - var ctx *feishu.App - - payload := []byte("{}") - header := http.Header{} - resp, err := document.CommentAddWhole(ctx, payload, header) - - fmt.Println(resp, err) -} diff --git a/apis/capabilities/document/file/example_file_test.go b/apis/capabilities/document/file/example_file_test.go new file mode 100644 index 0000000..8183b39 --- /dev/null +++ b/apis/capabilities/document/file/example_file_test.go @@ -0,0 +1,41 @@ +package file_test + +import ( + "fmt" + "net/url" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/apis/capabilities/document/file" +) + +func ExampleCreate() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := file.Create(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleCopy() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := file.Copy(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleDeleteDoc() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := file.DeleteDoc(ctx, params, accessToken) + + fmt.Println(resp, err) +} diff --git a/apis/capabilities/document/file/file.go b/apis/capabilities/document/file/file.go new file mode 100644 index 0000000..365f665 --- /dev/null +++ b/apis/capabilities/document/file/file.go @@ -0,0 +1,95 @@ +// Package file 云文档/file +package file + +import ( + "bytes" + "net/http" + "net/url" + "strings" + + "github.com/fastwego/feishu" +) + +const ( + apiCreate = "/open-apis/drive/explorer/v2/file/:folderToken" + apiCopy = "/open-apis/drive/explorer/v2/file/copy/files/:fileToken" + apiDeleteDoc = "/open-apis/drive/explorer/v2/file/docs/:docToken" +) + +/* +新建文档 + + +该接口用于根据 folderToken 创建 Doc或 Sheet 。 + +若没有特定的文件夹用于承载创建的文档,可以先调用「获取文件夹元信息」文档中的「获取 root folder (我的空间) meta」接口,获得我的空间的 token,然后再使用此接口。创建的文档将会在「我的空间」的「归我所有」列表里。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQTNzUjL0UzM14CN1MTN + +POST https://open.feishu.cn/open-apis/drive/explorer/v2/file/:folderToken +*/ +func Create(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiCreate + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +复制文档 + + + +该接口用于根据文件 token 复制 Doc 或 Sheet 到目标文件夹中。 + +若没有特定的文件夹用于承载创建的文档,可以先调用「获取文件夹元信息」文档中的「获取 root folder (我的空间) meta」接口,获得我的空间的 token,然后再使用此接口。复制的文档将会在「我的空间」的「归我所有」列表里。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTNzUjL2UzM14iN1MTN + +POST https://open.feishu.cn/open-apis/drive/explorer/v2/file/copy/files/:fileToken +*/ +func Copy(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiCopy + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +删除 Doc + +该接口用于根据 docToken 删除对应的 Docs 文档。 + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATM2UjLwEjN14CMxYTN + +DELETE https://open.feishu.cn/open-apis/drive/explorer/v2/file/docs/:docToken +*/ +func DeleteDoc(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiDeleteDoc + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPDelete(feishu.FeishuServerUrl+api, header) +} diff --git a/apis/capabilities/document/file/file_test.go b/apis/capabilities/document/file/file_test.go new file mode 100644 index 0000000..2ff94d5 --- /dev/null +++ b/apis/capabilities/document/file/file_test.go @@ -0,0 +1,134 @@ +package file + +import ( + "net/http" + "net/url" + "os" + "reflect" + "testing" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/test" +) + +func TestMain(m *testing.M) { + test.Setup() + os.Exit(m.Run()) +} + +func TestCreate(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiCreate, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := Create(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("Create() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("Create() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestCopy(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiCopy, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := Copy(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("Copy() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("Copy() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestDeleteDoc(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiDeleteDoc, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("DELETE") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := DeleteDoc(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("DeleteDoc() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("DeleteDoc() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} diff --git a/apis/capabilities/document/folder/example_folder_test.go b/apis/capabilities/document/folder/example_folder_test.go new file mode 100644 index 0000000..b62c5f8 --- /dev/null +++ b/apis/capabilities/document/folder/example_folder_test.go @@ -0,0 +1,49 @@ +package folder_test + +import ( + "fmt" + "net/url" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/apis/capabilities/document/folder" +) + +func ExampleCreate() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := folder.Create(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleMeta() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := folder.Meta(ctx, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleRootFolderMeta() { + var ctx *feishu.App + + accessToken := "" + resp, err := folder.RootFolderMeta(ctx, accessToken) + + fmt.Println(resp, err) +} + +func ExampleChildren() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := folder.Children(ctx, params, accessToken) + + fmt.Println(resp, err) +} diff --git a/apis/capabilities/document/folder/folder.go b/apis/capabilities/document/folder/folder.go new file mode 100644 index 0000000..5bbf77b --- /dev/null +++ b/apis/capabilities/document/folder/folder.go @@ -0,0 +1,112 @@ +// Package folder 云文档/folder +package folder + +import ( + "bytes" + "net/http" + "net/url" + "strings" + + "github.com/fastwego/feishu" +) + +const ( + apiCreate = "/open-apis/drive/explorer/v2/folder/:folderToken" + apiMeta = "/open-apis/drive/explorer/v2/folder/:folderToken/meta" + apiRootFolderMeta = "/open-apis/drive/explorer/v2/root_folder/meta" + apiChildren = "/open-apis/drive/explorer/v2/folder/:folderToken/children" +) + +/* +新建文件夹 + + + +该接口用于根据 folderToken 在该 folder 下创建文件夹 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTNzUjL5UzM14SO1MTN + +POST https://open.feishu.cn/open-apis/drive/explorer/v2/folder/:folderToken +*/ +func Create(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiCreate + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +获取文件夹元信息 + + +该接口用于根据 folderToken 获取该文件夹的元信息 + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNzUjLwYzM14CM2MTN + +GET https://open.feishu.cn/open-apis/drive/explorer/v2/folder/:folderToken/meta +*/ +func Meta(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiMeta + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) +} + +/* +获取root folder(我的空间) meta + +该接口用于获取 "我的空间" 的元信息 + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNzUjLwYzM14CM2MTN + +GET https://open.feishu.cn/open-apis/drive/explorer/v2/root_folder/meta +*/ +func RootFolderMeta(ctx *feishu.App, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiRootFolderMeta, header) +} + +/* +获取文件夹下的文档清单 + + + +该接口用于根据 folderToken 获取该文件夹的文档清单,如 doc、sheet、folder + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjNzUjLxYzM14SM2MTN + +GET https://open.feishu.cn/open-apis/drive/explorer/v2/folder/:folderToken/children +*/ +func Children(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiChildren + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api+"?"+params.Encode(), header) +} diff --git a/apis/capabilities/document/folder/folder_test.go b/apis/capabilities/document/folder/folder_test.go new file mode 100644 index 0000000..93ea5f6 --- /dev/null +++ b/apis/capabilities/document/folder/folder_test.go @@ -0,0 +1,170 @@ +package folder + +import ( + "net/http" + "net/url" + "os" + "reflect" + "testing" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/test" +) + +func TestMain(m *testing.M) { + test.Setup() + os.Exit(m.Run()) +} + +func TestCreate(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiCreate, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := Create(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("Create() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("Create() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMeta(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMeta, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := Meta(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("Meta() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("Meta() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestRootFolderMeta(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiRootFolderMeta, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := RootFolderMeta(tt.args.ctx, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("RootFolderMeta() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("RootFolderMeta() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestChildren(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiChildren, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := Children(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("Children() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("Children() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} diff --git a/apis/capabilities/document/permission/example_permission_test.go b/apis/capabilities/document/permission/example_permission_test.go new file mode 100644 index 0000000..4485b76 --- /dev/null +++ b/apis/capabilities/document/permission/example_permission_test.go @@ -0,0 +1,78 @@ +package permission_test + +import ( + "fmt" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/apis/capabilities/document/permission" +) + +func ExampleMemberCreate() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := permission.MemberCreate(ctx, payload, accessToken) + + fmt.Println(resp, err) +} + +func ExampleMemberTransfer() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := permission.MemberTransfer(ctx, payload, accessToken) + + fmt.Println(resp, err) +} + +func ExamplePublicUpdate() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := permission.PublicUpdate(ctx, payload, accessToken) + + fmt.Println(resp, err) +} + +func ExampleMemberList() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := permission.MemberList(ctx, payload, accessToken) + + fmt.Println(resp, err) +} + +func ExampleMemberDelete() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := permission.MemberDelete(ctx, payload, accessToken) + + fmt.Println(resp, err) +} + +func ExampleMemberUpdate() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := permission.MemberUpdate(ctx, payload, accessToken) + + fmt.Println(resp, err) +} + +func ExampleMemberPermitted() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := permission.MemberPermitted(ctx, payload, accessToken) + + fmt.Println(resp, err) +} diff --git a/apis/capabilities/document/permission/permission.go b/apis/capabilities/document/permission/permission.go new file mode 100644 index 0000000..ad1b2f7 --- /dev/null +++ b/apis/capabilities/document/permission/permission.go @@ -0,0 +1,168 @@ +// Package permission 云文档/permission +package permission + +import ( + "bytes" + "net/http" + + "github.com/fastwego/feishu" +) + +const ( + apiMemberCreate = "/open-apis/drive/permission/member/create" + apiMemberTransfer = "/open-apis/drive/permission/member/transfer" + apiPublicUpdate = "/open-apis/drive/permission/public/update" + apiMemberList = "/open-apis/drive/permission/member/list" + apiMemberDelete = "/open-apis/drive/permission/member/delete" + apiMemberUpdate = "/open-apis/drive/permission/member/update" + apiMemberPermitted = "/open-apis/drive/permission/member/permitted" +) + +/* +增加权限 + + + +该接口用于根据 filetoken 给用户增加文档的权限 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMzNzUjLzczM14yM3MTN + +POST https://open.feishu.cn/open-apis/drive/permission/member/create +*/ +func MemberCreate(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMemberCreate, bytes.NewReader(payload), header) +} + +/* +转移拥有者 + + + +该接口用于根据文档信息和用户信息转移文档的所有者。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQzNzUjL0czM14CN3MTN + +POST https://open.feishu.cn/open-apis/drive/permission/member/transfer +*/ +func MemberTransfer(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMemberTransfer, bytes.NewReader(payload), header) +} + +/* +更新文档公共设置 + + + +该接口用于根据 filetoken 更新文档的公共设置 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTM3UjL5EzN14SOxcTN + +POST https://open.feishu.cn/open-apis/drive/permission/public/update +*/ +func PublicUpdate(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiPublicUpdate, bytes.NewReader(payload), header) +} + +/* +获取协作者列表 + + + +该接口用于根据 filetoken 查询协作者,目前包括人('user')和群('chat') + +**你能获取到协作者列表的前提是你对该文档有权限** + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATN3UjLwUzN14CM1cTN + +POST https://open.feishu.cn/open-apis/drive/permission/member/list +*/ +func MemberList(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMemberList, bytes.NewReader(payload), header) +} + +/* +移除协作者权限 + + + +该接口用于根据 filetoken 移除文档协作者的权限 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTN3UjL2UzN14iN1cTN + +POST https://open.feishu.cn/open-apis/drive/permission/member/delete +*/ +func MemberDelete(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMemberDelete, bytes.NewReader(payload), header) +} + +/* +更新协作者权限 + + + +该接口用于根据 filetoken 更新文档协作者的权限 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucTN3UjL3UzN14yN1cTN + +POST https://open.feishu.cn/open-apis/drive/permission/member/update +*/ +func MemberUpdate(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMemberUpdate, bytes.NewReader(payload), header) +} + +/* +判断协作者是否有某权限 + + + +该接口用于根据 filetoken 判断当前登录用户是否具有某权限 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYzN3UjL2czN14iN3cTN + +POST https://open.feishu.cn/open-apis/drive/permission/member/permitted +*/ +func MemberPermitted(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMemberPermitted, bytes.NewReader(payload), header) +} diff --git a/apis/capabilities/document/permission/permission_test.go b/apis/capabilities/document/permission/permission_test.go new file mode 100644 index 0000000..2ae272f --- /dev/null +++ b/apis/capabilities/document/permission/permission_test.go @@ -0,0 +1,276 @@ +package permission + +import ( + "net/http" + "os" + "reflect" + "testing" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/test" +) + +func TestMain(m *testing.M) { + test.Setup() + os.Exit(m.Run()) +} + +func TestMemberCreate(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMemberCreate, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MemberCreate(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MemberCreate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MemberCreate() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMemberTransfer(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMemberTransfer, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MemberTransfer(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MemberTransfer() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MemberTransfer() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestPublicUpdate(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiPublicUpdate, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := PublicUpdate(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("PublicUpdate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("PublicUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMemberList(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMemberList, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MemberList(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MemberList() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MemberList() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMemberDelete(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMemberDelete, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MemberDelete(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MemberDelete() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MemberDelete() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMemberUpdate(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMemberUpdate, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MemberUpdate(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MemberUpdate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MemberUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMemberPermitted(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMemberPermitted, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MemberPermitted(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MemberPermitted() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MemberPermitted() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} diff --git a/apis/capabilities/document/platform/example_platform_test.go b/apis/capabilities/document/platform/example_platform_test.go new file mode 100644 index 0000000..590cde6 --- /dev/null +++ b/apis/capabilities/document/platform/example_platform_test.go @@ -0,0 +1,28 @@ +package platform_test + +import ( + "fmt" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/apis/capabilities/document/platform" +) + +func ExampleDocsMeta() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := platform.DocsMeta(ctx, payload, accessToken) + + fmt.Println(resp, err) +} + +func ExampleSearchObject() { + var ctx *feishu.App + + payload := []byte("{}") + accessToken := "" + resp, err := platform.SearchObject(ctx, payload, accessToken) + + fmt.Println(resp, err) +} diff --git a/apis/capabilities/document/platform/platform.go b/apis/capabilities/document/platform/platform.go new file mode 100644 index 0000000..9b8c873 --- /dev/null +++ b/apis/capabilities/document/platform/platform.go @@ -0,0 +1,56 @@ +// Package platform 云文档/platform +package platform + +import ( + "bytes" + "net/http" + + "github.com/fastwego/feishu" +) + +const ( + apiDocsMeta = "/open-apis/suite/docs-api/meta" + apiSearchObject = "/open-apis/suite/docs-api/search/object" +) + +/* +获取元数据 + + + +该接口用于根据 token 获取各类文件的元数据 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjN3UjLzYzN14yM2cTN + +POST https://open.feishu.cn/open-apis/suite/docs-api/meta +*/ +func DocsMeta(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiDocsMeta, bytes.NewReader(payload), header) +} + +/* +文档搜索 + + + +该接口用于根据搜索条件进行文档搜索 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDM4UjL4ADO14COwgTN + +POST https://open.feishu.cn/open-apis/suite/docs-api/search/object +*/ +func SearchObject(ctx *feishu.App, payload []byte, accessToken string) (resp []byte, err error) { + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiSearchObject, bytes.NewReader(payload), header) +} diff --git a/apis/capabilities/document/platform/platform_test.go b/apis/capabilities/document/platform/platform_test.go new file mode 100644 index 0000000..c6ac1fb --- /dev/null +++ b/apis/capabilities/document/platform/platform_test.go @@ -0,0 +1,91 @@ +package platform + +import ( + "net/http" + "os" + "reflect" + "testing" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/test" +) + +func TestMain(m *testing.M) { + test.Setup() + os.Exit(m.Run()) +} + +func TestDocsMeta(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiDocsMeta, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := DocsMeta(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("DocsMeta() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("DocsMeta() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestSearchObject(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiSearchObject, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := SearchObject(tt.args.ctx, tt.args.payload, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("SearchObject() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("SearchObject() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} diff --git a/apis/capabilities/document/sheets/example_sheets_test.go b/apis/capabilities/document/sheets/example_sheets_test.go new file mode 100644 index 0000000..74de929 --- /dev/null +++ b/apis/capabilities/document/sheets/example_sheets_test.go @@ -0,0 +1,203 @@ +package sheets_test + +import ( + "fmt" + "net/url" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/apis/capabilities/document/sheets" +) + +func ExampleMetaInfo() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := sheets.MetaInfo(ctx, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleUpdateProperties() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.UpdateProperties(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleBatchUpdate() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.BatchUpdate(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleValuesPrepend() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.ValuesPrepend(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleValuesAppend() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.ValuesAppend(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleInsertDimensionRange() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.InsertDimensionRange(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleCreateDimensionRange() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.CreateDimensionRange(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleUpdateDimensionRange() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.UpdateDimensionRange(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleDeleteDimensionRange() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := sheets.DeleteDimensionRange(ctx, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleUpdateStyle() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.UpdateStyle(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleBatchUpdateStyle() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.BatchUpdateStyle(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleProtectedDimension() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.ProtectedDimension(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleMergeCells() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.MergeCells(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleUnmergeCells() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.UnmergeCells(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleRange() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := sheets.Range(ctx, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleValues() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.Values(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleValuesBatchGet() { + var ctx *feishu.App + + params := url.Values{} + accessToken := "" + resp, err := sheets.ValuesBatchGet(ctx, params, accessToken) + + fmt.Println(resp, err) +} + +func ExampleValuesBatchUpdate() { + var ctx *feishu.App + + payload := []byte("{}") + params := url.Values{} + accessToken := "" + resp, err := sheets.ValuesBatchUpdate(ctx, payload, params, accessToken) + + fmt.Println(resp, err) +} diff --git a/apis/capabilities/document/sheets/sheets.go b/apis/capabilities/document/sheets/sheets.go new file mode 100644 index 0000000..9aa02d5 --- /dev/null +++ b/apis/capabilities/document/sheets/sheets.go @@ -0,0 +1,485 @@ +// Package sheets 云文档/sheets +package sheets + +import ( + "bytes" + "net/http" + "net/url" + "strings" + + "github.com/fastwego/feishu" +) + +const ( + apiMetaInfo = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/metainfo" + apiUpdateProperties = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/properties" + apiBatchUpdate = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/sheets_batch_update" + apiValuesPrepend = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_prepend" + apiValuesAppend = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_append" + apiInsertDimensionRange = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/insert_dimension_range" + apiCreateDimensionRange = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range" + apiUpdateDimensionRange = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range" + apiDeleteDimensionRange = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range" + apiUpdateStyle = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/style" + apiBatchUpdateStyle = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/styles_batch_update" + apiProtectedDimension = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/protected_dimension" + apiMergeCells = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/merge_cells" + apiUnmergeCells = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/unmerge_cells" + apiRange = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values/:range" + apiValues = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values" + apiValuesBatchGet = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_get" + apiValuesBatchUpdate = "/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_update" +) + +/* +获取表格元数据 + + +该接口用于根据 spreadsheetToken 获取表格元数据。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uETMzUjLxEzM14SMxMTN + +GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/metainfo +*/ +func MetaInfo(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiMetaInfo + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) +} + +/* +更新表格属性 + +该接口用于根据 spreadsheetToken 更新表格属性,如更新表格标题。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucTMzUjL3EzM14yNxMTN + +PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/properties +*/ +func UpdateProperties(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiUpdateProperties + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPut(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +操作子表/更新子表属性 + + + +该接口用于根据 spreadsheetToken 操作表格,如增加sheet,复制sheet、删除sheet。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTMzUjL2EzM14iNxMTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/sheets_batch_update +*/ +func BatchUpdate(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiBatchUpdate + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +插入数据 + + + +该接口用于根据 spreadsheetToken 和 range 向范围之前增加相应数据的行和相应的数据,相当于数组的插入操作;单次写入不超过5000行,100列,每个格子大小为0.5M。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIjMzUjLyIzM14iMyMTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_prepend +*/ +func ValuesPrepend(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiValuesPrepend + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +追加数据 + + + +该接口用于根据 spreadsheetToken 和 range 遇到空行则进行覆盖追加或新增行追加数据。 空行:默认该行第一个格子是空,则认为是空行;单次写入不超过5000行,100列,每个格子大小为0.5M。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjMzUjLzIzM14yMyMTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_append +*/ +func ValuesAppend(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiValuesAppend + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +插入行列 + + + +该接口用于根据 spreadsheetToken 和维度信息 插入空行/列 。如 startIndex=3, endIndex=7,则从第 4 行开始开始插入行列,一直到第 7 行,共插入 4 行;单次操作不超过5000行或列。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQjMzUjL0IzM14CNyMTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/insert_dimension_range +*/ +func InsertDimensionRange(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiInsertDimensionRange + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +增加行列 + + + +该接口用于根据 spreadsheetToken 和长度,在末尾增加空行/列;单次操作不超过5000行或列。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUjMzUjL1IzM14SNyMTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range +*/ +func CreateDimensionRange(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiCreateDimensionRange + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +更新行列 + +该接口用于根据 spreadsheetToken 和维度信息更新隐藏行列、单元格大小;单次操作不超过5000行或列。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYjMzUjL2IzM14iNyMTN + +PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range +*/ +func UpdateDimensionRange(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiUpdateDimensionRange + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPut(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +删除行列 + +该接口用于根据 spreadsheetToken 和维度信息删除行/列 。单次删除最大5000行/列。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucjMzUjL3IzM14yNyMTN + +DELETE https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range +*/ +func DeleteDimensionRange(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiDeleteDimensionRange + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPDelete(feishu.FeishuServerUrl+api, header) +} + +/* +设置单元格样式 + +该接口用于根据 spreadsheetToken 、range 和样式信息更新单元格样式;单次写入不超过5000行,100列。 + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukjMzUjL5IzM14SOyMTN + +PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/style +*/ +func UpdateStyle(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiUpdateStyle + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPut(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +批量设置单元格样式 + +该接口用于根据 spreadsheetToken 、range和样式信息 批量更新单元格样式;单次写入不超过5000行,100列。 + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAzMzUjLwMzM14CMzMTN + +PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/styles_batch_update +*/ +func BatchUpdateStyle(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiBatchUpdateStyle + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPut(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +增加锁定单元格 + + + +该接口用于根据 spreadsheetToken 和维度信息增加多个范围的锁定单元格;单次操作不超过5000行或列。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDNzUjL4QzM14CO0MTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/protected_dimension +*/ +func ProtectedDimension(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiProtectedDimension + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +合并单元格 + + + +该接口用于根据 spreadsheetToken 和维度信息合并单元格;单次操作不超过5000行,100列。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukDNzUjL5QzM14SO0MTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/merge_cells +*/ +func MergeCells(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiMergeCells + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +拆分单元格 + + + +该接口用于根据 spreadsheetToken 和维度信息拆分单元格;单次操作不超过5000行,100列。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATNzUjLwUzM14CM1MTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/unmerge_cells +*/ +func UnmergeCells(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiUnmergeCells + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +读取单个范围 + + + +该接口用于根据 spreadsheetToken 和 range 读取表格单个范围的值,返回数据限制为10M。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugTMzUjL4EzM14COxMTN + +GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values/:range +*/ +func Range(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiRange + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api, header) +} + +/* +向单个范围写入数据 + +该接口用于根据 spreadsheetToken 和 range 向单个范围写入数据,若范围内有数据,将被更新覆盖;单次写入不超过5000行,100列,每个格子大小为0.5M。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjMzUjLwIzM14CMyMTN + +PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values +*/ +func Values(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiValues + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPut(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} + +/* +读取多个范围 + + + +该接口用于根据 spreadsheetToken 和 ranges 读取表格多个范围的值,返回数据限制为10M。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTMzUjL5EzM14SOxMTN + +GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_get +*/ +func ValuesBatchGet(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiValuesBatchGet + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+api+"?"+params.Encode(), header) +} + +/* +向多个范围写入数据 + + + +该接口用于根据 spreadsheetToken 和 range 向多个范围写入数据,若范围内有数据,将被更新覆盖;单次写入不超过5000行,100列,每个格子大小为0.5M。 + + +See: https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjMzUjLxIzM14SMyMTN + +POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_update +*/ +func ValuesBatchUpdate(ctx *feishu.App, payload []byte, params url.Values, accessToken string) (resp []byte, err error) { + + api := apiValuesBatchUpdate + for paramName, paramValues := range params { + api = strings.ReplaceAll(api, ":"+paramName, paramValues[0]) + } + + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+api, bytes.NewReader(payload), header) +} diff --git a/apis/capabilities/document/sheets/sheets_test.go b/apis/capabilities/document/sheets/sheets_test.go new file mode 100644 index 0000000..33295e0 --- /dev/null +++ b/apis/capabilities/document/sheets/sheets_test.go @@ -0,0 +1,716 @@ +package sheets + +import ( + "net/http" + "net/url" + "os" + "reflect" + "testing" + + "github.com/fastwego/feishu" + "github.com/fastwego/feishu/test" +) + +func TestMain(m *testing.M) { + test.Setup() + os.Exit(m.Run()) +} + +func TestMetaInfo(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMetaInfo, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MetaInfo(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MetaInfo() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MetaInfo() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestUpdateProperties(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiUpdateProperties, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("PUT") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := UpdateProperties(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("UpdateProperties() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("UpdateProperties() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestBatchUpdate(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiBatchUpdate, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := BatchUpdate(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("BatchUpdate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("BatchUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestValuesPrepend(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiValuesPrepend, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := ValuesPrepend(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("ValuesPrepend() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("ValuesPrepend() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestValuesAppend(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiValuesAppend, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := ValuesAppend(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("ValuesAppend() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("ValuesAppend() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestInsertDimensionRange(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiInsertDimensionRange, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := InsertDimensionRange(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("InsertDimensionRange() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("InsertDimensionRange() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestCreateDimensionRange(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiCreateDimensionRange, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := CreateDimensionRange(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("CreateDimensionRange() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("CreateDimensionRange() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestUpdateDimensionRange(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiUpdateDimensionRange, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("PUT") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := UpdateDimensionRange(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("UpdateDimensionRange() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("UpdateDimensionRange() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestDeleteDimensionRange(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiDeleteDimensionRange, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("DELETE") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := DeleteDimensionRange(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("DeleteDimensionRange() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("DeleteDimensionRange() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestUpdateStyle(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiUpdateStyle, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("PUT") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := UpdateStyle(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("UpdateStyle() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("UpdateStyle() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestBatchUpdateStyle(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiBatchUpdateStyle, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("PUT") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := BatchUpdateStyle(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("BatchUpdateStyle() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("BatchUpdateStyle() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestProtectedDimension(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiProtectedDimension, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := ProtectedDimension(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("ProtectedDimension() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("ProtectedDimension() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestMergeCells(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiMergeCells, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := MergeCells(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("MergeCells() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("MergeCells() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestUnmergeCells(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiUnmergeCells, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := UnmergeCells(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("UnmergeCells() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("UnmergeCells() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestRange(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiRange, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := Range(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("Range() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("Range() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestValues(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiValues, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("PUT") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := Values(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("Values() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("Values() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestValuesBatchGet(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiValuesBatchGet, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("GET") + + type args struct { + ctx *feishu.App + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := ValuesBatchGet(tt.args.ctx, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("ValuesBatchGet() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("ValuesBatchGet() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} +func TestValuesBatchUpdate(t *testing.T) { + mockResp := map[string][]byte{ + "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), + } + var resp []byte + test.MockRouter.HandleFunc(apiValuesBatchUpdate, func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(resp)) + }).Methods("POST") + + type args struct { + ctx *feishu.App + payload []byte + + params url.Values + accessToken string + } + tests := []struct { + name string + args args + wantResp []byte + wantErr bool + }{ + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp = mockResp[tt.name] + gotResp, err := ValuesBatchUpdate(tt.args.ctx, tt.args.payload, tt.args.params, tt.args.accessToken) + //fmt.Println(string(gotResp), err) + if (err != nil) != tt.wantErr { + t.Errorf("ValuesBatchUpdate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("ValuesBatchUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) + } + }) + } +} diff --git a/apis/capabilities/meeting/example_meeting_test.go b/apis/capabilities/meeting_room/example_meeting_room_test.go similarity index 70% rename from apis/capabilities/meeting/example_meeting_test.go rename to apis/capabilities/meeting_room/example_meeting_room_test.go index 8348bd5..b6f9277 100644 --- a/apis/capabilities/meeting/example_meeting_test.go +++ b/apis/capabilities/meeting_room/example_meeting_room_test.go @@ -12,22 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -package meeting_test +package meeting_room_test import ( "fmt" "net/url" "github.com/fastwego/feishu" - "github.com/fastwego/feishu/apis/capabilities/meeting" + "github.com/fastwego/feishu/apis/capabilities/meeting_room" ) func ExampleBuildingList() { var ctx *feishu.App params := url.Values{} - - resp, err := meeting.BuildingList(ctx, params) + resp, err := meeting_room.BuildingList(ctx, params) fmt.Println(resp, err) } @@ -36,8 +35,7 @@ func ExampleBuildingBatchGet() { var ctx *feishu.App params := url.Values{} - - resp, err := meeting.BuildingBatchGet(ctx, params) + resp, err := meeting_room.BuildingBatchGet(ctx, params) fmt.Println(resp, err) } @@ -46,8 +44,7 @@ func ExampleMeetingRoomList() { var ctx *feishu.App params := url.Values{} - - resp, err := meeting.MeetingRoomList(ctx, params) + resp, err := meeting_room.MeetingRoomList(ctx, params) fmt.Println(resp, err) } @@ -56,8 +53,7 @@ func ExampleMeetingRoomBatchGet() { var ctx *feishu.App params := url.Values{} - - resp, err := meeting.MeetingRoomBatchGet(ctx, params) + resp, err := meeting_room.MeetingRoomBatchGet(ctx, params) fmt.Println(resp, err) } @@ -66,8 +62,7 @@ func ExampleMeetingRoomFreeBusyBatchGet() { var ctx *feishu.App params := url.Values{} - - resp, err := meeting.MeetingRoomFreeBusyBatchGet(ctx, params) + resp, err := meeting_room.MeetingRoomFreeBusyBatchGet(ctx, params) fmt.Println(resp, err) } @@ -76,8 +71,7 @@ func ExampleInstanceReply() { var ctx *feishu.App payload := []byte("{}") - - resp, err := meeting.InstanceReply(ctx, payload) + resp, err := meeting_room.InstanceReply(ctx, payload) fmt.Println(resp, err) } @@ -86,8 +80,7 @@ func ExampleBuildingCreate() { var ctx *feishu.App payload := []byte("{}") - - resp, err := meeting.BuildingCreate(ctx, payload) + resp, err := meeting_room.BuildingCreate(ctx, payload) fmt.Println(resp, err) } @@ -96,8 +89,7 @@ func ExampleBuildingUpdate() { var ctx *feishu.App payload := []byte("{}") - - resp, err := meeting.BuildingUpdate(ctx, payload) + resp, err := meeting_room.BuildingUpdate(ctx, payload) fmt.Println(resp, err) } @@ -106,8 +98,7 @@ func ExampleBuildingDelete() { var ctx *feishu.App payload := []byte("{}") - - resp, err := meeting.BuildingDelete(ctx, payload) + resp, err := meeting_room.BuildingDelete(ctx, payload) fmt.Println(resp, err) } @@ -116,8 +107,7 @@ func ExampleBuildingBatchGetById() { var ctx *feishu.App params := url.Values{} - - resp, err := meeting.BuildingBatchGetById(ctx, params) + resp, err := meeting_room.BuildingBatchGetById(ctx, params) fmt.Println(resp, err) } @@ -126,8 +116,7 @@ func ExampleMeetingRoomCreate() { var ctx *feishu.App payload := []byte("{}") - - resp, err := meeting.MeetingRoomCreate(ctx, payload) + resp, err := meeting_room.MeetingRoomCreate(ctx, payload) fmt.Println(resp, err) } @@ -136,8 +125,7 @@ func ExampleMeetingRoomUpdate() { var ctx *feishu.App payload := []byte("{}") - - resp, err := meeting.MeetingRoomUpdate(ctx, payload) + resp, err := meeting_room.MeetingRoomUpdate(ctx, payload) fmt.Println(resp, err) } @@ -146,8 +134,7 @@ func ExampleMeetingRoomDelete() { var ctx *feishu.App payload := []byte("{}") - - resp, err := meeting.MeetingRoomDelete(ctx, payload) + resp, err := meeting_room.MeetingRoomDelete(ctx, payload) fmt.Println(resp, err) } @@ -156,8 +143,7 @@ func ExampleMeetingRoomBatchGetById() { var ctx *feishu.App params := url.Values{} - - resp, err := meeting.MeetingRoomBatchGetById(ctx, params) + resp, err := meeting_room.MeetingRoomBatchGetById(ctx, params) fmt.Println(resp, err) } @@ -165,7 +151,7 @@ func ExampleMeetingRoomBatchGetById() { func ExampleCountryList() { var ctx *feishu.App - resp, err := meeting.CountryList(ctx) + resp, err := meeting_room.CountryList(ctx) fmt.Println(resp, err) } @@ -174,8 +160,7 @@ func ExampleDistrictList() { var ctx *feishu.App params := url.Values{} - - resp, err := meeting.DistrictList(ctx, params) + resp, err := meeting_room.DistrictList(ctx, params) fmt.Println(resp, err) } diff --git a/apis/capabilities/meeting/meeting.go b/apis/capabilities/meeting_room/meeting_room.go similarity index 82% rename from apis/capabilities/meeting/meeting.go rename to apis/capabilities/meeting_room/meeting_room.go index aa383a8..b0acd7a 100644 --- a/apis/capabilities/meeting/meeting.go +++ b/apis/capabilities/meeting_room/meeting_room.go @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package meeting 会议室 -package meeting +// Package meeting_room 会议室 +package meeting_room import ( "bytes" @@ -63,9 +63,9 @@ func BuildingList(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiBuildingList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiBuildingList+"?"+params.Encode(), header) } /* @@ -89,9 +89,9 @@ func BuildingBatchGet(ctx *feishu.App, params url.Values) (resp []byte, err erro } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiBuildingBatchGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiBuildingBatchGet+"?"+params.Encode(), header) } /* @@ -115,9 +115,9 @@ func MeetingRoomList(ctx *feishu.App, params url.Values) (resp []byte, err error } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiMeetingRoomList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiMeetingRoomList+"?"+params.Encode(), header) } /* @@ -141,9 +141,9 @@ func MeetingRoomBatchGet(ctx *feishu.App, params url.Values) (resp []byte, err e } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiMeetingRoomBatchGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiMeetingRoomBatchGet+"?"+params.Encode(), header) } /* @@ -167,9 +167,9 @@ func MeetingRoomFreeBusyBatchGet(ctx *feishu.App, params url.Values) (resp []byt } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiMeetingRoomFreeBusyBatchGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiMeetingRoomFreeBusyBatchGet+"?"+params.Encode(), header) } /* @@ -193,9 +193,9 @@ func InstanceReply(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiInstanceReply, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiInstanceReply, bytes.NewReader(payload), header) } /* @@ -219,9 +219,9 @@ func BuildingCreate(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiBuildingCreate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiBuildingCreate, bytes.NewReader(payload), header) } /* @@ -245,9 +245,9 @@ func BuildingUpdate(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiBuildingUpdate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiBuildingUpdate, bytes.NewReader(payload), header) } /* @@ -271,9 +271,9 @@ func BuildingDelete(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiBuildingDelete, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiBuildingDelete, bytes.NewReader(payload), header) } /* @@ -297,9 +297,9 @@ func BuildingBatchGetById(ctx *feishu.App, params url.Values) (resp []byte, err } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiBuildingBatchGetById+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiBuildingBatchGetById+"?"+params.Encode(), header) } /* @@ -323,9 +323,9 @@ func MeetingRoomCreate(ctx *feishu.App, payload []byte) (resp []byte, err error) } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiMeetingRoomCreate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMeetingRoomCreate, bytes.NewReader(payload), header) } /* @@ -349,9 +349,9 @@ func MeetingRoomUpdate(ctx *feishu.App, payload []byte) (resp []byte, err error) } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiMeetingRoomUpdate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMeetingRoomUpdate, bytes.NewReader(payload), header) } /* @@ -375,9 +375,9 @@ func MeetingRoomDelete(ctx *feishu.App, payload []byte) (resp []byte, err error) } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiMeetingRoomDelete, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiMeetingRoomDelete, bytes.NewReader(payload), header) } /* @@ -401,9 +401,9 @@ func MeetingRoomBatchGetById(ctx *feishu.App, params url.Values) (resp []byte, e } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiMeetingRoomBatchGetById+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiMeetingRoomBatchGetById+"?"+params.Encode(), header) } /* @@ -427,9 +427,9 @@ func CountryList(ctx *feishu.App) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiCountryList, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiCountryList, header) } /* @@ -453,7 +453,7 @@ func DistrictList(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiDistrictList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiDistrictList+"?"+params.Encode(), header) } diff --git a/apis/capabilities/meeting/meeting_test.go b/apis/capabilities/meeting_room/meeting_room_test.go similarity index 90% rename from apis/capabilities/meeting/meeting_test.go rename to apis/capabilities/meeting_room/meeting_room_test.go index c353857..1906106 100644 --- a/apis/capabilities/meeting/meeting_test.go +++ b/apis/capabilities/meeting_room/meeting_room_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package meeting +package meeting_room import ( "net/http" @@ -35,9 +35,9 @@ func TestBuildingList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBuildingList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBuildingList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -72,9 +72,9 @@ func TestBuildingBatchGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBuildingBatchGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBuildingBatchGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -109,9 +109,9 @@ func TestMeetingRoomList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiMeetingRoomList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiMeetingRoomList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -146,9 +146,9 @@ func TestMeetingRoomBatchGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiMeetingRoomBatchGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiMeetingRoomBatchGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -183,9 +183,9 @@ func TestMeetingRoomFreeBusyBatchGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiMeetingRoomFreeBusyBatchGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiMeetingRoomFreeBusyBatchGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -220,9 +220,9 @@ func TestInstanceReply(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiInstanceReply, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiInstanceReply, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -256,9 +256,9 @@ func TestBuildingCreate(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBuildingCreate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBuildingCreate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -292,9 +292,9 @@ func TestBuildingUpdate(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBuildingUpdate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBuildingUpdate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -328,9 +328,9 @@ func TestBuildingDelete(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBuildingDelete, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBuildingDelete, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -364,9 +364,9 @@ func TestBuildingBatchGetById(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBuildingBatchGetById, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBuildingBatchGetById, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -401,9 +401,9 @@ func TestMeetingRoomCreate(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiMeetingRoomCreate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiMeetingRoomCreate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -437,9 +437,9 @@ func TestMeetingRoomUpdate(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiMeetingRoomUpdate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiMeetingRoomUpdate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -473,9 +473,9 @@ func TestMeetingRoomDelete(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiMeetingRoomDelete, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiMeetingRoomDelete, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -509,9 +509,9 @@ func TestMeetingRoomBatchGetById(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiMeetingRoomBatchGetById, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiMeetingRoomBatchGetById, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -546,9 +546,9 @@ func TestCountryList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiCountryList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiCountryList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -581,9 +581,9 @@ func TestDistrictList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDistrictList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDistrictList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App diff --git a/apis/contact/async_batch/async_batch.go b/apis/contact/async_batch/async_batch.go index c82f1ba..6a557ff 100644 --- a/apis/contact/async_batch/async_batch.go +++ b/apis/contact/async_batch/async_batch.go @@ -51,9 +51,9 @@ func DepartmentBatchAdd(ctx *feishu.App, payload []byte) (resp []byte, err error } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiDepartmentBatchAdd, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiDepartmentBatchAdd, bytes.NewReader(payload), header) } /* @@ -78,9 +78,9 @@ func UserBatchAdd(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiUserBatchAdd, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiUserBatchAdd, bytes.NewReader(payload), header) } /* @@ -104,7 +104,7 @@ func TaskGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiTaskGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiTaskGet+"?"+params.Encode(), header) } diff --git a/apis/contact/async_batch/async_batch_test.go b/apis/contact/async_batch/async_batch_test.go index 56d9e23..d7c96b3 100644 --- a/apis/contact/async_batch/async_batch_test.go +++ b/apis/contact/async_batch/async_batch_test.go @@ -35,9 +35,9 @@ func TestDepartmentBatchAdd(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentBatchAdd, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDepartmentBatchAdd, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -71,9 +71,9 @@ func TestUserBatchAdd(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiUserBatchAdd, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiUserBatchAdd, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -107,9 +107,9 @@ func TestTaskGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiTaskGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiTaskGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App diff --git a/apis/contact/async_batch/example_async_batch_test.go b/apis/contact/async_batch/example_async_batch_test.go index 964a0c4..976da3c 100644 --- a/apis/contact/async_batch/example_async_batch_test.go +++ b/apis/contact/async_batch/example_async_batch_test.go @@ -26,7 +26,6 @@ func ExampleDepartmentBatchAdd() { var ctx *feishu.App payload := []byte("{}") - resp, err := async_batch.DepartmentBatchAdd(ctx, payload) fmt.Println(resp, err) @@ -36,7 +35,6 @@ func ExampleUserBatchAdd() { var ctx *feishu.App payload := []byte("{}") - resp, err := async_batch.UserBatchAdd(ctx, payload) fmt.Println(resp, err) @@ -46,7 +44,6 @@ func ExampleTaskGet() { var ctx *feishu.App params := url.Values{} - resp, err := async_batch.TaskGet(ctx, params) fmt.Println(resp, err) diff --git a/apis/contact/contact.go b/apis/contact/contact.go index e8f9aba..b71dc12 100644 --- a/apis/contact/contact.go +++ b/apis/contact/contact.go @@ -51,7 +51,7 @@ func TenantCustomAttrGet(ctx *feishu.App) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiTenantCustomAttrGet, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiTenantCustomAttrGet, header) } diff --git a/apis/contact/contact_test.go b/apis/contact/contact_test.go index d938b3d..3f14a83 100644 --- a/apis/contact/contact_test.go +++ b/apis/contact/contact_test.go @@ -34,9 +34,9 @@ func TestTenantCustomAttrGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiTenantCustomAttrGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiTenantCustomAttrGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App diff --git a/apis/contact/department/department.go b/apis/contact/department/department.go index b6330ea..49a3e53 100644 --- a/apis/contact/department/department.go +++ b/apis/contact/department/department.go @@ -24,12 +24,12 @@ import ( ) const ( - apiDepartmentInfoGet = "/open-apis/contact/v1/department/info/get" - apiDepartmentSimpleList = "/open-apis/contact/v1/department/simple/list" - apiDepartmentDetailBatchGet = "/open-apis/contact/v1/department/detail/batch_get" - apiDepartmentAdd = "/open-apis/contact/v1/department/add" - apiDepartmentDelete = "/open-apis/contact/v1/department/delete" - apiDepartmentUpdate = "/open-apis/contact/v1/department/update" + apiInfoGet = "/open-apis/contact/v1/department/info/get" + apiSimpleList = "/open-apis/contact/v1/department/simple/list" + apiDetailBatchGet = "/open-apis/contact/v1/department/detail/batch_get" + apiAdd = "/open-apis/contact/v1/department/add" + apiDelete = "/open-apis/contact/v1/department/delete" + apiUpdate = "/open-apis/contact/v1/department/update" ) /* @@ -44,7 +44,7 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/uAzNz4CM3MjLwczM GET https://open.feishu.cn/open-apis/contact/v1/department/info/get?department_id=TT-1234 */ -func DepartmentInfoGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { +func InfoGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -52,9 +52,9 @@ func DepartmentInfoGet(ctx *feishu.App, params url.Values) (resp []byte, err err } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiDepartmentInfoGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiInfoGet+"?"+params.Encode(), header) } /* @@ -70,7 +70,7 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/ugzN3QjL4czN04CO3cDN GET https://open.feishu.cn/open-apis/contact/v1/department/simple/list?department_id=TT-1234&page_size=10&fetch_child=true */ -func DepartmentSimpleList(ctx *feishu.App, params url.Values) (resp []byte, err error) { +func SimpleList(ctx *feishu.App, params url.Values) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -78,9 +78,9 @@ func DepartmentSimpleList(ctx *feishu.App, params url.Values) (resp []byte, err } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiDepartmentSimpleList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiSimpleList+"?"+params.Encode(), header) } /* @@ -95,7 +95,7 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/uczN3QjL3czN04yN3cDN GET https://open.feishu.cn/open-apis/contact/v1/department/detail/batch_get?department_ids=od-2efe30807a10608754862a63b108828f&department_ids=od-da6427b2adbceb91204d7fa6aeb7e8ff */ -func DepartmentDetailBatchGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { +func DetailBatchGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -103,9 +103,9 @@ func DepartmentDetailBatchGet(ctx *feishu.App, params url.Values) (resp []byte, } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiDepartmentDetailBatchGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiDetailBatchGet+"?"+params.Encode(), header) } /* @@ -122,7 +122,7 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/uYzNz4iN3MjL2czM POST https://open.feishu.cn/open-apis/contact/v1/department/add */ -func DepartmentAdd(ctx *feishu.App, payload []byte) (resp []byte, err error) { +func Add(ctx *feishu.App, payload []byte) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -130,9 +130,9 @@ func DepartmentAdd(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiDepartmentAdd, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiAdd, bytes.NewReader(payload), header) } /* @@ -148,7 +148,7 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/ugzNz4CO3MjL4czM POST https://open.feishu.cn/open-apis/contact/v1/department/delete */ -func DepartmentDelete(ctx *feishu.App, payload []byte) (resp []byte, err error) { +func Delete(ctx *feishu.App, payload []byte) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -156,9 +156,9 @@ func DepartmentDelete(ctx *feishu.App, payload []byte) (resp []byte, err error) } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiDepartmentDelete, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiDelete, bytes.NewReader(payload), header) } /* @@ -174,7 +174,7 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/uczNz4yN3MjL3czM POST https://open.feishu.cn/open-apis/contact/v1/department/update */ -func DepartmentUpdate(ctx *feishu.App, payload []byte) (resp []byte, err error) { +func Update(ctx *feishu.App, payload []byte) (resp []byte, err error) { accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -182,7 +182,7 @@ func DepartmentUpdate(ctx *feishu.App, payload []byte) (resp []byte, err error) } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiDepartmentUpdate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiUpdate, bytes.NewReader(payload), header) } diff --git a/apis/contact/department/department_test.go b/apis/contact/department/department_test.go index 1bd090a..c5a76f1 100644 --- a/apis/contact/department/department_test.go +++ b/apis/contact/department/department_test.go @@ -30,14 +30,14 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func TestDepartmentInfoGet(t *testing.T) { +func TestInfoGet(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentInfoGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiInfoGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -55,26 +55,26 @@ func TestDepartmentInfoGet(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := DepartmentInfoGet(tt.args.ctx, tt.args.params) + gotResp, err := InfoGet(tt.args.ctx, tt.args.params) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("DepartmentInfoGet() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("InfoGet() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DepartmentInfoGet() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("InfoGet() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } } -func TestDepartmentSimpleList(t *testing.T) { +func TestSimpleList(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentSimpleList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiSimpleList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -92,26 +92,26 @@ func TestDepartmentSimpleList(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := DepartmentSimpleList(tt.args.ctx, tt.args.params) + gotResp, err := SimpleList(tt.args.ctx, tt.args.params) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("DepartmentSimpleList() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("SimpleList() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DepartmentSimpleList() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("SimpleList() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } } -func TestDepartmentDetailBatchGet(t *testing.T) { +func TestDetailBatchGet(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentDetailBatchGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDetailBatchGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -129,26 +129,26 @@ func TestDepartmentDetailBatchGet(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := DepartmentDetailBatchGet(tt.args.ctx, tt.args.params) + gotResp, err := DetailBatchGet(tt.args.ctx, tt.args.params) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("DepartmentDetailBatchGet() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("DetailBatchGet() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DepartmentDetailBatchGet() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("DetailBatchGet() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } } -func TestDepartmentAdd(t *testing.T) { +func TestAdd(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentAdd, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAdd, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -165,26 +165,26 @@ func TestDepartmentAdd(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := DepartmentAdd(tt.args.ctx, tt.args.payload) + gotResp, err := Add(tt.args.ctx, tt.args.payload) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("DepartmentAdd() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Add() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DepartmentAdd() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("Add() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } } -func TestDepartmentDelete(t *testing.T) { +func TestDelete(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentDelete, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDelete, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -201,26 +201,26 @@ func TestDepartmentDelete(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := DepartmentDelete(tt.args.ctx, tt.args.payload) + gotResp, err := Delete(tt.args.ctx, tt.args.payload) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("DepartmentDelete() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DepartmentDelete() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("Delete() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } } -func TestDepartmentUpdate(t *testing.T) { +func TestUpdate(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentUpdate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiUpdate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -237,14 +237,14 @@ func TestDepartmentUpdate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := DepartmentUpdate(tt.args.ctx, tt.args.payload) + gotResp, err := Update(tt.args.ctx, tt.args.payload) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { - t.Errorf("DepartmentUpdate() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Update() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("DepartmentUpdate() gotResp = %v, want %v", gotResp, tt.wantResp) + t.Errorf("Update() gotResp = %v, want %v", gotResp, tt.wantResp) } }) } diff --git a/apis/contact/department/example_department_test.go b/apis/contact/department/example_department_test.go index 8a7a376..f195f76 100644 --- a/apis/contact/department/example_department_test.go +++ b/apis/contact/department/example_department_test.go @@ -22,62 +22,56 @@ import ( "github.com/fastwego/feishu/apis/contact/department" ) -func ExampleDepartmentInfoGet() { +func ExampleInfoGet() { var ctx *feishu.App params := url.Values{} - - resp, err := department.DepartmentInfoGet(ctx, params) + resp, err := department.InfoGet(ctx, params) fmt.Println(resp, err) } -func ExampleDepartmentSimpleList() { +func ExampleSimpleList() { var ctx *feishu.App params := url.Values{} - - resp, err := department.DepartmentSimpleList(ctx, params) + resp, err := department.SimpleList(ctx, params) fmt.Println(resp, err) } -func ExampleDepartmentDetailBatchGet() { +func ExampleDetailBatchGet() { var ctx *feishu.App params := url.Values{} - - resp, err := department.DepartmentDetailBatchGet(ctx, params) + resp, err := department.DetailBatchGet(ctx, params) fmt.Println(resp, err) } -func ExampleDepartmentAdd() { +func ExampleAdd() { var ctx *feishu.App payload := []byte("{}") - - resp, err := department.DepartmentAdd(ctx, payload) + resp, err := department.Add(ctx, payload) fmt.Println(resp, err) } -func ExampleDepartmentDelete() { +func ExampleDelete() { var ctx *feishu.App payload := []byte("{}") - - resp, err := department.DepartmentDelete(ctx, payload) + resp, err := department.Delete(ctx, payload) fmt.Println(resp, err) } -func ExampleDepartmentUpdate() { +func ExampleUpdate() { var ctx *feishu.App payload := []byte("{}") - - resp, err := department.DepartmentUpdate(ctx, payload) + resp, err := department.Update(ctx, payload) fmt.Println(resp, err) } diff --git a/apis/contact/user/example_user_test.go b/apis/contact/user/example_user_test.go index d4fb9ea..911a3e3 100644 --- a/apis/contact/user/example_user_test.go +++ b/apis/contact/user/example_user_test.go @@ -16,7 +16,6 @@ package user_test import ( "fmt" - "net/http" "net/url" "github.com/fastwego/feishu" @@ -27,7 +26,6 @@ func ExampleBatchGet() { var ctx *feishu.App params := url.Values{} - resp, err := user.BatchGet(ctx, params) fmt.Println(resp, err) @@ -37,7 +35,6 @@ func ExampleDepartmentUserList() { var ctx *feishu.App params := url.Values{} - resp, err := user.DepartmentUserList(ctx, params) fmt.Println(resp, err) @@ -47,7 +44,6 @@ func ExampleDepartmentUserDetailList() { var ctx *feishu.App params := url.Values{} - resp, err := user.DepartmentUserDetailList(ctx, params) fmt.Println(resp, err) @@ -57,7 +53,6 @@ func ExampleAdd() { var ctx *feishu.App payload := []byte("{}") - resp, err := user.Add(ctx, payload) fmt.Println(resp, err) @@ -67,7 +62,6 @@ func ExampleDelete() { var ctx *feishu.App payload := []byte("{}") - resp, err := user.Delete(ctx, payload) fmt.Println(resp, err) @@ -77,7 +71,6 @@ func ExampleUpdate() { var ctx *feishu.App payload := []byte("{}") - resp, err := user.Update(ctx, payload) fmt.Println(resp, err) @@ -95,7 +88,6 @@ func ExampleRoleMembers() { var ctx *feishu.App params := url.Values{} - resp, err := user.RoleMembers(ctx, params) fmt.Println(resp, err) @@ -105,7 +97,6 @@ func ExampleBatchGetId() { var ctx *feishu.App params := url.Values{} - resp, err := user.BatchGetId(ctx, params) fmt.Println(resp, err) @@ -115,7 +106,6 @@ func ExampleUnionIdBatchGetList() { var ctx *feishu.App params := url.Values{} - resp, err := user.UnionIdBatchGetList(ctx, params) fmt.Println(resp, err) @@ -125,8 +115,8 @@ func ExampleSearch() { var ctx *feishu.App params := url.Values{} - header := http.Header{} - resp, err := user.Search(ctx, params, header) + accessToken := "" + resp, err := user.Search(ctx, params, accessToken) fmt.Println(resp, err) } diff --git a/apis/contact/user/user.go b/apis/contact/user/user.go index 2a73a40..db441fb 100644 --- a/apis/contact/user/user.go +++ b/apis/contact/user/user.go @@ -58,9 +58,9 @@ func BatchGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiBatchGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiBatchGet+"?"+params.Encode(), header) } /* @@ -83,9 +83,9 @@ func DepartmentUserList(ctx *feishu.App, params url.Values) (resp []byte, err er } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiDepartmentUserList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiDepartmentUserList+"?"+params.Encode(), header) } /* @@ -108,9 +108,9 @@ func DepartmentUserDetailList(ctx *feishu.App, params url.Values) (resp []byte, } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiDepartmentUserDetailList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiDepartmentUserDetailList+"?"+params.Encode(), header) } /* @@ -134,9 +134,9 @@ func Add(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiAdd, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiAdd, bytes.NewReader(payload), header) } /* @@ -161,9 +161,9 @@ func Delete(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiDelete, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiDelete, bytes.NewReader(payload), header) } /* @@ -188,9 +188,9 @@ func Update(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiUpdate, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiUpdate, bytes.NewReader(payload), header) } /* @@ -214,9 +214,9 @@ func RoleList(ctx *feishu.App) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiRoleList, header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiRoleList, header) } /* @@ -240,9 +240,9 @@ func RoleMembers(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiRoleMembers+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiRoleMembers+"?"+params.Encode(), header) } /* @@ -270,9 +270,9 @@ func BatchGetId(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiBatchGetId+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiBatchGetId+"?"+params.Encode(), header) } /* @@ -295,9 +295,9 @@ func UnionIdBatchGetList(ctx *feishu.App, params url.Values) (resp []byte, err e } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiUnionIdBatchGetList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiUnionIdBatchGetList+"?"+params.Encode(), header) } /* @@ -312,9 +312,11 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/uMTM4UjLzEDO14yMxgTN GET https://open.feishu.cn/open-apis/search/v1/user?query=zhangsan&page_size=20&page_token=20 */ -func Search(ctx *feishu.App, params url.Values, header http.Header) (resp []byte, err error) { +func Search(ctx *feishu.App, params url.Values, accessToken string) (resp []byte, err error) { - header.Set("Content-appType", "application/json") + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiSearch+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiSearch+"?"+params.Encode(), header) } diff --git a/apis/contact/user/user_test.go b/apis/contact/user/user_test.go index b0b86c1..03a5e42 100644 --- a/apis/contact/user/user_test.go +++ b/apis/contact/user/user_test.go @@ -35,9 +35,9 @@ func TestBatchGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBatchGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBatchGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -72,9 +72,9 @@ func TestDepartmentUserList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentUserList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDepartmentUserList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -109,9 +109,9 @@ func TestDepartmentUserDetailList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDepartmentUserDetailList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDepartmentUserDetailList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -146,9 +146,9 @@ func TestAdd(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAdd, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAdd, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -182,9 +182,9 @@ func TestDelete(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiDelete, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiDelete, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -218,9 +218,9 @@ func TestUpdate(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiUpdate, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiUpdate, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -254,9 +254,9 @@ func TestRoleList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiRoleList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiRoleList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -289,9 +289,9 @@ func TestRoleMembers(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiRoleMembers, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiRoleMembers, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -326,9 +326,9 @@ func TestBatchGetId(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBatchGetId, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBatchGetId, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -363,9 +363,9 @@ func TestUnionIdBatchGetList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiUnionIdBatchGetList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiUnionIdBatchGetList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -400,15 +400,15 @@ func TestSearch(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiSearch, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiSearch, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App - params url.Values - header http.Header + params url.Values + accessToken string } tests := []struct { name string @@ -416,12 +416,12 @@ func TestSearch(t *testing.T) { wantResp []byte wantErr bool }{ - {name: "case1", args: args{ctx: test.MockApp, header: http.Header{}}, wantResp: mockResp["case1"], wantErr: false}, + {name: "case1", args: args{ctx: test.MockApp, accessToken: "USER_ACCESS_TOKEN"}, wantResp: mockResp["case1"], wantErr: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp = mockResp[tt.name] - gotResp, err := Search(tt.args.ctx, tt.args.params, tt.args.header) + gotResp, err := Search(tt.args.ctx, tt.args.params, tt.args.accessToken) //fmt.Println(string(gotResp), err) if (err != nil) != tt.wantErr { t.Errorf("Search() error = %v, wantErr %v", err, tt.wantErr) diff --git a/apis/message/example_message_test.go b/apis/message/example_message_test.go index de15fa4..44ac3ef 100644 --- a/apis/message/example_message_test.go +++ b/apis/message/example_message_test.go @@ -26,7 +26,6 @@ func ExampleBatchSend() { var ctx *feishu.App payload := []byte("{}") - resp, err := message.BatchSend(ctx, payload) fmt.Println(resp, err) @@ -36,7 +35,6 @@ func ExampleSend() { var ctx *feishu.App payload := []byte("{}") - resp, err := message.Send(ctx, payload) fmt.Println(resp, err) @@ -46,27 +44,15 @@ func ExampleReadInfo() { var ctx *feishu.App payload := []byte("{}") - resp, err := message.ReadInfo(ctx, payload) fmt.Println(resp, err) } -func ExampleImagePut() { - var ctx *feishu.App - - payload := []byte("{}") - - resp, err := message.ImagePut(ctx, payload) - - fmt.Println(resp, err) -} - func ExampleImageGet() { var ctx *feishu.App params := url.Values{} - resp, err := message.ImageGet(ctx, params) fmt.Println(resp, err) @@ -76,7 +62,6 @@ func ExampleFileGet() { var ctx *feishu.App params := url.Values{} - resp, err := message.FileGet(ctx, params) fmt.Println(resp, err) @@ -86,7 +71,6 @@ func ExampleAppNotify() { var ctx *feishu.App payload := []byte("{}") - resp, err := message.AppNotify(ctx, payload) fmt.Println(resp, err) diff --git a/apis/message/message.go b/apis/message/message.go index 16d06dc..fddc611 100644 --- a/apis/message/message.go +++ b/apis/message/message.go @@ -17,8 +17,12 @@ package message import ( "bytes" + "io" + "mime/multipart" "net/http" "net/url" + "os" + "path" "github.com/fastwego/feishu" ) @@ -55,16 +59,16 @@ func BatchSend(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiBatchSend, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiBatchSend, bytes.NewReader(payload), header) } /* -发送文本消息 +发送消息 -给指定用户或者会话发送文本消息,其中会话包括私聊会话和群会话。 +给指定用户或者会话发送文本/图片/富文本/群名片/消息卡片 消息,其中会话包括私聊会话和群会话。 **权限说明** :需要启用机器人能力;私聊会话时机器人需要拥有对用户的可见性,群会话需要机器人在群里 @@ -81,9 +85,9 @@ func Send(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiSend, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiSend, bytes.NewReader(payload), header) } /* @@ -107,9 +111,9 @@ func ReadInfo(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiReadInfo, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiReadInfo, bytes.NewReader(payload), header) } /* @@ -125,7 +129,34 @@ See: https://open.feishu.cn/document/ukTMukTMukTM/uEDO04SM4QjLxgDN POST https://open.feishu.cn/open-apis/image/v4/put/ */ -func ImagePut(ctx *feishu.App, payload []byte) (resp []byte, err error) { +func ImagePut(ctx *feishu.App, image string, params url.Values) (resp []byte, err error) { + + r, w := io.Pipe() + m := multipart.NewWriter(w) + go func() { + defer w.Close() + defer m.Close() + + part, err := m.CreateFormFile("image", path.Base(image)) + if err != nil { + return + } + file, err := os.Open(image) + if err != nil { + return + } + defer file.Close() + if _, err = io.Copy(part, file); err != nil { + return + } + + // field + err = m.WriteField("image_type", params.Get("image_type")) + if err != nil { + return + } + + }() accessToken, err := ctx.GetTenantAccessTokenHandler() if err != nil { @@ -133,9 +164,9 @@ func ImagePut(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", m.FormDataContentType()) - return ctx.Client.HTTPPost(apiImagePut, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiImagePut, r, header) } /* @@ -159,9 +190,9 @@ func ImageGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiImageGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiImageGet+"?"+params.Encode(), header) } /* @@ -185,9 +216,9 @@ func FileGet(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiFileGet+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiFileGet+"?"+params.Encode(), header) } /* @@ -210,7 +241,7 @@ func AppNotify(ctx *feishu.App, payload []byte) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPPost(apiAppNotify, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiAppNotify, bytes.NewReader(payload), header) } diff --git a/apis/message/message_test.go b/apis/message/message_test.go index 9ce7fa1..0c68ce0 100644 --- a/apis/message/message_test.go +++ b/apis/message/message_test.go @@ -35,9 +35,9 @@ func TestBatchSend(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiBatchSend, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiBatchSend, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -71,9 +71,9 @@ func TestSend(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiSend, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiSend, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -107,9 +107,9 @@ func TestReadInfo(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiReadInfo, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiReadInfo, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App @@ -138,50 +138,14 @@ func TestReadInfo(t *testing.T) { }) } } -func TestImagePut(t *testing.T) { - mockResp := map[string][]byte{ - "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), - } - var resp []byte - test.MockSvrHandler.HandleFunc(apiImagePut, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(resp)) - }) - - type args struct { - ctx *feishu.App - payload []byte - } - tests := []struct { - name string - args args - wantResp []byte - wantErr bool - }{ - {name: "case1", args: args{ctx: test.MockApp}, wantResp: mockResp["case1"], wantErr: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - resp = mockResp[tt.name] - gotResp, err := ImagePut(tt.args.ctx, tt.args.payload) - //fmt.Println(string(gotResp), err) - if (err != nil) != tt.wantErr { - t.Errorf("ImagePut() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotResp, tt.wantResp) { - t.Errorf("ImagePut() gotResp = %v, want %v", gotResp, tt.wantResp) - } - }) - } -} func TestImageGet(t *testing.T) { mockResp := map[string][]byte{ "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiImageGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiImageGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -216,9 +180,9 @@ func TestFileGet(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiFileGet, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiFileGet, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -253,9 +217,9 @@ func TestAppNotify(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiAppNotify, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiAppNotify, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("POST") type args struct { ctx *feishu.App diff --git a/apis/user_group/example_user_group_test.go b/apis/user_group/example_user_group_test.go index 4fac870..dd9b030 100644 --- a/apis/user_group/example_user_group_test.go +++ b/apis/user_group/example_user_group_test.go @@ -26,7 +26,6 @@ func ExampleGroupList() { var ctx *feishu.App params := url.Values{} - resp, err := user_group.GroupList(ctx, params) fmt.Println(resp, err) @@ -36,7 +35,6 @@ func ExampleMembers() { var ctx *feishu.App params := url.Values{} - resp, err := user_group.Members(ctx, params) fmt.Println(resp, err) @@ -46,7 +44,6 @@ func ExampleSearch() { var ctx *feishu.App params := url.Values{} - resp, err := user_group.Search(ctx, params) fmt.Println(resp, err) diff --git a/apis/user_group/user_group.go b/apis/user_group/user_group.go index b3782b2..9d44304 100644 --- a/apis/user_group/user_group.go +++ b/apis/user_group/user_group.go @@ -48,9 +48,9 @@ func GroupList(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiGroupList+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiGroupList+"?"+params.Encode(), header) } /* @@ -73,9 +73,9 @@ func Members(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiMembers+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiMembers+"?"+params.Encode(), header) } /* @@ -98,7 +98,7 @@ func Search(ctx *feishu.App, params url.Values) (resp []byte, err error) { } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") - return ctx.Client.HTTPGet(apiSearch+"?"+params.Encode(), header) + return ctx.Client.HTTPGet(feishu.FeishuServerUrl+apiSearch+"?"+params.Encode(), header) } diff --git a/apis/user_group/user_group_test.go b/apis/user_group/user_group_test.go index 776b8d6..83c2d36 100644 --- a/apis/user_group/user_group_test.go +++ b/apis/user_group/user_group_test.go @@ -35,9 +35,9 @@ func TestGroupList(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiGroupList, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiGroupList, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -72,9 +72,9 @@ func TestMembers(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiMembers, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiMembers, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App @@ -109,9 +109,9 @@ func TestSearch(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(apiSearch, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(apiSearch, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("GET") type args struct { ctx *feishu.App diff --git a/client.go b/client.go index d896c62..08f48df 100644 --- a/client.go +++ b/client.go @@ -15,6 +15,7 @@ package feishu import ( + "bytes" "encoding/json" "errors" "fmt" @@ -27,6 +28,7 @@ import ( 飞书 api 服务器地址 */ var FeishuServerUrl = "https://open.feishu.cn" +var FeishuServerUrl2 = "https://www.feishu.cn" /* HttpClient 用于向 接口发送请求 @@ -36,63 +38,72 @@ type Client struct { } // HTTPGet GET 请求 -func (client *Client) HTTPGet(uri string, header http.Header) (resp []byte, err error) { - url := FeishuServerUrl + uri +func (client *Client) HTTPGet(url string, header http.Header) (resp []byte, err error) { - httpClient := &http.Client{} req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return } req.Header = header - if client.Ctx.Logger != nil { - client.Ctx.Logger.Printf("GET %s Headers %v", req.URL.String(), req.Header) - } - response, err := httpClient.Do(req) - if err != nil { - return - } - defer response.Body.Close() - return responseFilter(response) + return client.HTTPDo(req) } //HTTPPost POST 请求 -func (client *Client) HTTPPost(uri string, payload io.Reader, header http.Header) (resp []byte, err error) { - - url := FeishuServerUrl + uri +func (client *Client) HTTPPost(url string, payload io.Reader, header http.Header) (resp []byte, err error) { - httpClient := &http.Client{} req, err := http.NewRequest(http.MethodPost, url, payload) if err != nil { return } req.Header = header - if client.Ctx.Logger != nil { - client.Ctx.Logger.Printf("POST %s Headers %v", req.URL.String(), req.Header) + return client.HTTPDo(req) +} + +//HTTPDelete DELETE 请求 +func (client *Client) HTTPDelete(url string, header http.Header) (resp []byte, err error) { + + req, err := http.NewRequest(http.MethodDelete, url, nil) + if err != nil { + return } - response, err := httpClient.Do(req) + req.Header = header + + return client.HTTPDo(req) +} + +//HTTPPatch PATCH 请求 +func (client *Client) HTTPPatch(url string, payload io.Reader, header http.Header) (resp []byte, err error) { + + req, err := http.NewRequest(http.MethodPatch, url, payload) if err != nil { return } - defer response.Body.Close() - return responseFilter(response) + req.Header = header + + return client.HTTPDo(req) } -func (client *Client) HTTPDelete(uri string, header http.Header) (resp []byte, err error) { - url := FeishuServerUrl + uri +//HTTPut PUT 请求 +func (client *Client) HTTPPut(url string, payload io.Reader, header http.Header) (resp []byte, err error) { - httpClient := &http.Client{} - req, err := http.NewRequest(http.MethodDelete, url, nil) + req, err := http.NewRequest(http.MethodPut, url, payload) if err != nil { return } req.Header = header + return client.HTTPDo(req) +} + +//HTTPDo 执行 请求 +func (client *Client) HTTPDo(req *http.Request) (resp []byte, err error) { if client.Ctx.Logger != nil { - client.Ctx.Logger.Printf("DELETE %s Headers %v", req.URL.String(), req.Header) + client.Ctx.Logger.Printf("%s %s Headers %v", req.Method, req.URL.String(), req.Header) } + + httpClient := &http.Client{} response, err := httpClient.Do(req) if err != nil { return @@ -119,18 +130,20 @@ func responseFilter(response *http.Response) (resp []byte, err error) { return } - errorResponse := struct { - Code int64 `json:"code"` - Msg string `json:"msg"` - }{} - err = json.Unmarshal(resp, &errorResponse) - if err != nil { - return - } - - if errorResponse.Code != 0 { - err = errors.New(string(resp)) - return + if bytes.HasPrefix(resp, []byte(`{`)) { // 只针对 json 数据 + errorResponse := struct { + Code int64 `json:"code"` + Msg string `json:"msg"` + }{} + err = json.Unmarshal(resp, &errorResponse) + if err != nil { + return + } + + if errorResponse.Code != 0 { + err = errors.New(string(resp)) + return + } } return diff --git a/cmd/apiconfig.go b/cmd/apiconfig.go index 24faaa0..4606f6e 100644 --- a/cmd/apiconfig.go +++ b/cmd/apiconfig.go @@ -37,6 +37,55 @@ type ApiGroup struct { } var apiConfig = []ApiGroup{ + { + Name: `身份认证`, + Package: `authen`, + Apis: []Api{ + { + Name: "获取用户授权跳转链接", + Description: "应用请求用户身份验证时,需按如下方式构造登录链接,并引导用户跳转至此链接。飞书客户端内用户免登,系统浏览器内用户需完成扫码登录。登录成功后会生成登录预授权码 code,并作为参数重定向到重定向URL。", + Request: "GET https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri={REDIRECT_URI}&app_id={APPID}&state={STATE}", + See: "https://open.feishu.cn/document/ukTMukTMukTM/ukzN4UjL5cDO14SO3gTN", + FuncName: "GetRedirectUri", + GetParams: []Param{ + {Name: `app_id`, Type: `string`}, + {Name: `redirect_uri`, Type: `string`}, + {Name: `state`, Type: `string`}, + }, + }, + { + Name: "获取登录用户身份", + Description: "通过此接口获取登录预授权码 code 对应的登录用户身份。", + Request: "POST https://open.feishu.cn/open-apis/authen/v1/access_token", + See: "https://open.feishu.cn/document/ukTMukTMukTM/uEDO4UjLxgDO14SM4gTN", + FuncName: "GetAccessToken", + }, + { + Name: "刷新access_token", + Description: "该接口用于在 access_token 过期时用 refresh_token 重新获取 access_token。此时会返回新的 refresh_token,再次刷新 access_token 时需要使用新的 refresh_token。", + Request: "POST https://open.feishu.cn/open-apis/authen/v1/refresh_access_token", + See: "https://open.feishu.cn/document/ukTMukTMukTM/uQDO4UjL0gDO14CN4gTN", + FuncName: "RefreshAccessToken", + }, + { + Name: "获取用户信息(身份验证)", + Description: "此接口仅用于获取登录用户的信息。调用此接口需要在 Header 中带上 user_access_token。\n\n", + Request: "GET https://open.feishu.cn/open-apis/authen/v1/user_info", + See: "https://open.feishu.cn/document/ukTMukTMukTM/uIDO4UjLygDO14iM4gTN", + FuncName: "GetUserInfo", + GetParams: []Param{ + {Name: `user_access_token`, Type: `string`}, + }, + }, + { + Name: "小程序登录/code2session", + Description: "通过 login 接口获取到登录凭证后,开发者可以通过服务器发送请求的方式获取 session_key 和 openId", + Request: "POST https://open.feishu.cn/open-apis/mina/v2/tokenLoginValidate", + See: "https://open.feishu.cn/document/uYjL24iN/ukjM04SOyQjL5IDN", + FuncName: "Code2Session", + }, + }, + }, { Name: `用户管理`, Package: `contact/user`, @@ -210,7 +259,7 @@ var apiConfig = []ApiGroup{ `, Request: "GET https://open.feishu.cn/open-apis/contact/v1/department/info/get?department_id=TT-1234", See: "https://open.feishu.cn/document/ukTMukTMukTM/uAzNz4CM3MjLwczM", - FuncName: "DepartmentInfoGet", + FuncName: "InfoGet", GetParams: []Param{ {Name: `department_id`, Type: `string`}, }, @@ -224,7 +273,7 @@ var apiConfig = []ApiGroup{ `, Request: "GET https://open.feishu.cn/open-apis/contact/v1/department/simple/list?department_id=TT-1234&page_size=10&fetch_child=true", See: "https://open.feishu.cn/document/ukTMukTMukTM/ugzN3QjL4czN04CO3cDN", - FuncName: "DepartmentSimpleList", + FuncName: "SimpleList", GetParams: []Param{ {Name: `fetch_child`, Type: `string`}, {Name: `department_id`, Type: `string`}, @@ -239,7 +288,7 @@ var apiConfig = []ApiGroup{ `, Request: "GET https://open.feishu.cn/open-apis/contact/v1/department/detail/batch_get?department_ids=od-2efe30807a10608754862a63b108828f&department_ids=od-da6427b2adbceb91204d7fa6aeb7e8ff", See: "https://open.feishu.cn/document/ukTMukTMukTM/uczN3QjL3czN04yN3cDN", - FuncName: "DepartmentDetailBatchGet", + FuncName: "DetailBatchGet", GetParams: []Param{ {Name: `department_ids`, Type: `string`}, }, @@ -254,7 +303,7 @@ var apiConfig = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/contact/v1/department/add", See: "https://open.feishu.cn/document/ukTMukTMukTM/uYzNz4iN3MjL2czM", - FuncName: "DepartmentAdd", + FuncName: "Add", }, { Name: "删除部门", @@ -265,7 +314,7 @@ var apiConfig = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/contact/v1/department/delete", See: "https://open.feishu.cn/document/ukTMukTMukTM/ugzNz4CO3MjL4czM", - FuncName: "DepartmentDelete", + FuncName: "Delete", }, { Name: "更新部门信息", @@ -276,7 +325,7 @@ var apiConfig = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/contact/v1/department/update", See: "https://open.feishu.cn/document/ukTMukTMukTM/uczNz4yN3MjL3czM", - FuncName: "DepartmentUpdate", + FuncName: "Update", }, }, }, @@ -398,7 +447,7 @@ var apiConfig = []ApiGroup{ }, { Name: `应用信息/应用管理`, - Package: `appinfo/app_manage`, + Package: `app/app_manage`, Apis: []Api{ { Name: "校验应用管理员", @@ -408,6 +457,9 @@ var apiConfig = []ApiGroup{ Request: "GET https://open.feishu.cn/open-apis/application/v3/is_user_admin", See: "https://open.feishu.cn/document/ukTMukTMukTM/uITN1EjLyUTNx4iM1UTM", FuncName: "IsUserAdmin", + GetParams: []Param{ + {Name: `open_id`, Type: `string`}, + }, }, { Name: "获取应用管理员管理范围", @@ -491,8 +543,18 @@ var apiConfig = []ApiGroup{ }, { Name: `应用信息/应用商店`, - Package: `appinfo/appstore`, + Package: `app/app_store`, Apis: []Api{ + { + Name: "查询用户是否在应用开通范围", + Description: `该接口用于查询用户是否在企业管理员设置的使用该应用的范围中。如果设置的付费套餐是按人收费或者限制了最大人数,开放平台会引导企业管理员设置“付费功能开通范围”,本接口用于查询用户是否在企业管理员设置的使用该应用的范围中,可以通过此接口,在付费功能点入口判断是否允许某个用户进入使用。`, + Request: "GET https://open.feishu.cn/open-apis/pay/v1/paid_scope/check_user?open_id=ou_5ad573a6411d72b8305fda3a9c15c70e", + See: "https://open.feishu.cn/document/ukTMukTMukTM/uATNwUjLwUDM14CM1ATN", + FuncName: "CheckUser", + GetParams: []Param{ + {Name: `open_id`, Type: `string`}, + }, + }, { Name: "查询租户购买的付费方案", Description: `该接口用于分页查询应用租户下的已付费订单,每次购买对应一个唯一的订单,订单会记录购买的套餐的相关信息,业务方需要自行处理套餐的有效期和付费方案的升级。 @@ -543,6 +605,9 @@ var apiConfig = []ApiGroup{ Request: "GET https://open.feishu.cn/open-apis/chat/v4/list", See: "https://open.feishu.cn/document/ukTMukTMukTM/uITO5QjLykTO04iM5kDN", FuncName: "ChatList", + GetParams: []Param{ + {Name: `page_size`, Type: `page_size`}, + }, }, { Name: "获取群信息", @@ -652,9 +717,9 @@ var apiConfig = []ApiGroup{ FuncName: "BatchSend", }, { - Name: "发送文本消息", + Name: "发送消息", Description: ` -给指定用户或者会话发送文本消息,其中会话包括私聊会话和群会话。 +给指定用户或者会话发送文本/图片/富文本/群名片/消息卡片 消息,其中会话包括私聊会话和群会话。 **权限说明** :需要启用机器人能力;私聊会话时机器人需要拥有对用户的可见性,群会话需要机器人在群里 `, diff --git a/cmd/apiconfig2.go b/cmd/apiconfig2.go index c29a47d..cb44e26 100644 --- a/cmd/apiconfig2.go +++ b/cmd/apiconfig2.go @@ -39,6 +39,9 @@ var apiConfig2 = []ApiGroup{ Request: "GET https://open.feishu.cn/open-apis/calendar/v3/calendar_list", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMTM14yMxUjLzETN", FuncName: "CalendarList", + GetParams: []Param{ + {Name: `max_results`, Type: `string`}, + }, }, { Name: "创建日历", @@ -61,6 +64,18 @@ var apiConfig2 = []ApiGroup{ {Name: "", Type: "string"}, }, }, + { + Name: "更新日历", + Description: ` +该接口用于修改指定日历的信息。 +`, + Request: "PATCH https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTM14iNxUjL2ETN", + FuncName: "UpdateCalendarById", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, { Name: "获取日程", Description: ` @@ -85,6 +100,45 @@ var apiConfig2 = []ApiGroup{ {Name: "", Type: "string"}, }, }, + { + Name: "获取日程列表", + Description: ` +该接口用于获取指定日历下的日程列表。 +`, + Request: "GET https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/events", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTM14SOxUjL5ETN", + FuncName: "GetEvents", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + GetParams: []Param{ + {Name: `max_results`, Type: `string`}, + }, + }, + { + Name: "删除日程", + Description: ` +该接口用于删除指定日历下的日程。 +`, + Request: "DELETE https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/events/:eventId", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjM14CMyUjLwITN", + FuncName: "DeleteEventById", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "更新日程", + Description: ` +该接口用于更新日程信息。 +`, + Request: "PATCH https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/events/:eventId", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjM14SMyUjLxITN", + FuncName: "UpdateEventById", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, { Name: "邀请/移除日程参与者", Description: ` @@ -105,7 +159,19 @@ var apiConfig2 = []ApiGroup{ `, Request: "GET https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/acl", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjM14yMyUjLzITN", - FuncName: "Acl", + FuncName: "GetAcl", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "创建访问控制", + Description: ` +该接口用于邀请一个用户加入日历。 +`, + Request: "POST https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/acl", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQjM14CNyUjL0ITN", + FuncName: "CreateAcl", PathParams: []Param{ {Name: "", Type: "string"}, }, @@ -117,7 +183,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "DELETE https://open.feishu.cn/open-apis/calendar/v3/calendars/:calendarId/acl/:ruleId", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUjM14SNyUjL1ITN", - FuncName: "DeleteAclByRuleId", + FuncName: "DeleteAcl", PathParams: []Param{ {Name: "", Type: "string"}, }, @@ -158,8 +224,8 @@ var apiConfig2 = []ApiGroup{ }, }, { - Name: `云文档`, - Package: `capabilities/document`, + Name: `云文档/folder`, + Package: `capabilities/document/folder`, Apis: []Api{ { @@ -170,7 +236,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/explorer/v2/folder/:folderToken", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTNzUjL5UzM14SO1MTN", - FuncName: "CreateFolder", + FuncName: "Create", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -179,8 +245,18 @@ var apiConfig2 = []ApiGroup{ { Name: "获取文件夹元信息", Description: ` -# 获取root folder(我的空间) meta该接口用于获取 我的空间 的元信息 -`, +该接口用于根据 folderToken 获取该文件夹的元信息`, + Request: "GET https://open.feishu.cn/open-apis/drive/explorer/v2/folder/:folderToken/meta", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNzUjLwYzM14CM2MTN", + FuncName: "Meta", + AccessToken: "user", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "获取root folder(我的空间) meta", + Description: `该接口用于获取 "我的空间" 的元信息`, Request: "GET https://open.feishu.cn/open-apis/drive/explorer/v2/root_folder/meta", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNzUjLwYzM14CM2MTN", FuncName: "RootFolderMeta", @@ -194,12 +270,22 @@ var apiConfig2 = []ApiGroup{ `, Request: "GET https://open.feishu.cn/open-apis/drive/explorer/v2/folder/:folderToken/children", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjNzUjLxYzM14SM2MTN", - FuncName: "FolderChildren", + FuncName: "Children", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, }, + GetParams: []Param{ + {Name: `types`, Type: `string`}, + }, }, + }, + }, + { + Name: `云文档/file`, + Package: `capabilities/document/file`, + Apis: []Api{ + { Name: "新建文档", Description: ` @@ -209,7 +295,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/explorer/v2/file/:folderToken", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQTNzUjL0UzM14CN1MTN", - FuncName: "CreateFile", + FuncName: "Create", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -225,26 +311,30 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/explorer/v2/file/copy/files/:fileToken", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTNzUjL2UzM14iN1MTN", - FuncName: "CopyFile", + FuncName: "Copy", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, }, }, { - Name: "删除文档", - Description: `Doc - -该接口用于根据 spreadsheetToken 删除对应的 sheet 文档。 -`, - Request: "DELETE https://open.feishu.cn/open-apis/drive/explorer/v2/file/spreadsheets/:spreadsheetToken", + Name: "删除 Doc", + Description: `该接口用于根据 docToken 删除对应的 Docs 文档。`, + Request: "DELETE https://open.feishu.cn/open-apis/drive/explorer/v2/file/docs/:docToken", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATM2UjLwEjN14CMxYTN", - FuncName: "DeleteFile", + FuncName: "DeleteDoc", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, }, }, + }, + }, + { + Name: `云文档/permission`, + Package: `capabilities/document/permission`, + Apis: []Api{ + { Name: "增加权限", Description: ` @@ -253,7 +343,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/permission/member/create", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMzNzUjLzczM14yM3MTN", - FuncName: "PermissionMemberCreate", + FuncName: "MemberCreate", AccessToken: "user", }, { @@ -264,7 +354,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/permission/member/transfer", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQzNzUjL0czM14CN3MTN", - FuncName: "PermissionMemberTransfer", + FuncName: "MemberTransfer", AccessToken: "user", }, { @@ -275,7 +365,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/permission/public/update", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTM3UjL5EzN14SOxcTN", - FuncName: "PermissionPublicUpdate", + FuncName: "PublicUpdate", AccessToken: "user", }, { @@ -288,7 +378,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/permission/member/list", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATN3UjLwUzN14CM1cTN", - FuncName: "PermissionMemberList", + FuncName: "MemberList", AccessToken: "user", }, { @@ -299,7 +389,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/permission/member/delete", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTN3UjL2UzN14iN1cTN", - FuncName: "PermissionMemberDelete", + FuncName: "MemberDelete", AccessToken: "user", }, { @@ -310,7 +400,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/permission/member/update", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucTN3UjL3UzN14yN1cTN", - FuncName: "PermissionMemberUpdate", + FuncName: "MemberUpdate", AccessToken: "user", }, { @@ -321,9 +411,16 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/drive/permission/member/permitted", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYzN3UjL2czN14iN3cTN", - FuncName: "PermissionMemberPermitted", + FuncName: "MemberPermitted", AccessToken: "user", }, + }, + }, + { + Name: `云文档/docs`, + Package: `capabilities/document/docs`, + Apis: []Api{ + { Name: "获取文档文本内容", Description: ` @@ -339,9 +436,7 @@ var apiConfig2 = []ApiGroup{ }, { Name: "获取sheet@doc的元数据", - Description: `sheet@doc 的元数据 - -该接口用于根据 docToken 获取 sheet@doc 的元数据。 + Description: `该接口用于根据 docToken 获取 sheet@doc 的元数据。 `, Request: "GET https://open.feishu.cn/open-apis/doc/v2/:docToken/sheet_meta", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uADOzUjLwgzM14CM4MTN", @@ -364,6 +459,13 @@ var apiConfig2 = []ApiGroup{ {Name: "", Type: "string"}, }, }, + }, + }, + { + Name: `云文档/sheets`, + Package: `capabilities/document/sheets`, + Apis: []Api{ + { Name: "获取表格元数据", Description: ` @@ -371,21 +473,33 @@ var apiConfig2 = []ApiGroup{ `, Request: "GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/metainfo", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uETMzUjLxEzM14SMxMTN", - FuncName: "SpreadSheetsMetainfo", + FuncName: "MetaInfo", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, }, }, { - Name: "操作子表", + Name: "更新表格属性", + Description: `该接口用于根据 spreadsheetToken 更新表格属性,如更新表格标题。 +`, + Request: "PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/properties", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucTMzUjL3EzM14yNxMTN", + FuncName: "UpdateProperties", + AccessToken: "user", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "操作子表/更新子表属性", Description: ` 该接口用于根据 spreadsheetToken 操作表格,如增加sheet,复制sheet、删除sheet。 `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/sheets_batch_update", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTMzUjL2EzM14iNxMTN", - FuncName: "SheetsBatchUpdate", + FuncName: "BatchUpdate", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -399,7 +513,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_prepend", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIjMzUjLyIzM14iMyMTN", - FuncName: "SpreadSheetsValuesPrepend", + FuncName: "ValuesPrepend", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -413,7 +527,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_append", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjMzUjLzIzM14yMyMTN", - FuncName: "SpreadSheetsValuesAppend", + FuncName: "ValuesAppend", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -427,7 +541,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/insert_dimension_range", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQjMzUjL0IzM14CNyMTN", - FuncName: "SpreadSheetsInsertDimensionRange", + FuncName: "InsertDimensionRange", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -441,7 +555,53 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUjMzUjL1IzM14SNyMTN", - FuncName: "SpreadSheetsDimensionRange", + FuncName: "CreateDimensionRange", + AccessToken: "user", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "更新行列", + Description: `该接口用于根据 spreadsheetToken 和维度信息更新隐藏行列、单元格大小;单次操作不超过5000行或列。 +`, + Request: "PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYjMzUjL2IzM14iNyMTN", + FuncName: "UpdateDimensionRange", + AccessToken: "user", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "删除行列", + Description: `该接口用于根据 spreadsheetToken 和维度信息删除行/列 。单次删除最大5000行/列。 +`, + Request: "DELETE https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucjMzUjL3IzM14yNyMTN", + FuncName: "DeleteDimensionRange", + AccessToken: "user", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "设置单元格样式", + Description: `该接口用于根据 spreadsheetToken 、range 和样式信息更新单元格样式;单次写入不超过5000行,100列。`, + Request: "PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/style", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukjMzUjL5IzM14SOyMTN", + FuncName: "UpdateStyle", + AccessToken: "user", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "批量设置单元格样式", + Description: `该接口用于根据 spreadsheetToken 、range和样式信息 批量更新单元格样式;单次写入不超过5000行,100列。`, + Request: "PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/styles_batch_update", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAzMzUjLwMzM14CMzMTN", + FuncName: "BatchUpdateStyle", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -455,7 +615,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/protected_dimension", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDNzUjL4QzM14CO0MTN", - FuncName: "SpreadSheetsProtectedDimension", + FuncName: "ProtectedDimension", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -469,7 +629,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/merge_cells", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukDNzUjL5QzM14SO0MTN", - FuncName: "SpreadSheetsMergeCells", + FuncName: "MergeCells", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -483,7 +643,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/unmerge_cells", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATNzUjLwUzM14CM1MTN", - FuncName: "SpreadSheetsUnmergeCells", + FuncName: "UnmergeCells", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -497,7 +657,19 @@ var apiConfig2 = []ApiGroup{ `, Request: "GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values/:range", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugTMzUjL4EzM14COxMTN", - FuncName: "SpreadSheetsRange", + FuncName: "Range", + AccessToken: "user", + PathParams: []Param{ + {Name: "", Type: "string"}, + }, + }, + { + Name: "向单个范围写入数据", + Description: `该接口用于根据 spreadsheetToken 和 range 向单个范围写入数据,若范围内有数据,将被更新覆盖;单次写入不超过5000行,100列,每个格子大小为0.5M。 +`, + Request: "PUT https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjMzUjLwIzM14CMyMTN", + FuncName: "Values", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, @@ -511,11 +683,14 @@ var apiConfig2 = []ApiGroup{ `, Request: "GET https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_get", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTMzUjL5EzM14SOxMTN", - FuncName: "SpreadSheetsValuesBatchGet", + FuncName: "ValuesBatchGet", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, }, + GetParams: []Param{ + {Name: "ranges", Type: "string"}, + }, }, { Name: "向多个范围写入数据", @@ -525,12 +700,19 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_update", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjMzUjLxIzM14SMyMTN", - FuncName: "SpreadSheetsValuesBatchUpdate", + FuncName: "ValuesBatchUpdate", AccessToken: "user", PathParams: []Param{ {Name: "", Type: "string"}, }, }, + }, + }, + { + Name: `云文档/platform`, + Package: `capabilities/document/platform`, + Apis: []Api{ + { Name: "获取元数据", Description: ` @@ -553,6 +735,13 @@ var apiConfig2 = []ApiGroup{ FuncName: "SearchObject", AccessToken: "user", }, + }, + }, + { + Name: `云文档/评论`, + Package: `capabilities/document/comment`, + Apis: []Api{ + { Name: "添加全文评论", Description: ` @@ -561,14 +750,14 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://open.feishu.cn/open-apis/comment/add_whole", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucDN4UjL3QDO14yN0gTN", - FuncName: "CommentAddWhole", + FuncName: "AddWhole", AccessToken: "user", }, }, }, { Name: `审批`, - Package: `capabilities/approve`, + Package: `capabilities/approval`, Apis: []Api{ { @@ -669,18 +858,39 @@ var apiConfig2 = []ApiGroup{ FuncName: "Upload", }, { - Name: "三方审批实例同步", - Description: ` -用于第三方审批的实例同步。 -使用前需确保已经在审批后台创建第三方审批。 + Name: "三方审批定义创建/同步", + Description: `企业通过第三方审批定义创建接口,帮助企业创建审批定义,创建审批定义后,可以将该审批定义下的审批实例推送到飞书审批应用。 +`, + Request: "POST https://www.feishu.cn/approval/openapi/v3/external/approval/create", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIDNyYjLyQjM24iM0IjN", + FuncName: "ExternalInstanceCreate", + }, + { + Name: "三方审批实例校验", + Description: `校验三方审批实例数据,用于判断服务端数据是否为最新的。用户提交实例最新更新时间,如果服务端不存在该实例,或者服务端实例更新时间不是最新的,则返回对应实例 id。 -> 审批实例:员工发起审批时产生的对象,详情参见 [开发指南](/ssl:ttdoc/ugTM5UjL4ETO14COxkTN/ukDNyUjL5QjM14SO0ITN) -> +例如,用户可以每隔5分钟,将最近5分钟产生的实例使用该接口进行对比。 **权限说明** :需要获取 访问审批应用 权限。 `, - Request: "POST https://www.feishu.cn/approval/openapi/v2/external/instance/create", - See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uczM3UjL3MzN14yNzcTN", - FuncName: "ExternalInstanceCreate", + Request: "POST https://www.feishu.cn/approval/openapi/v3/external/instance/check", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUDNyYjL1QjM24SN0IjN", + FuncName: "ExternalInstanceCheck", + }, + { + Name: "发送审批Bot消息", + Description: `此接口可以用来通过飞书审批的Bot推送消息给用户,当有新的审批待办,或者审批待办的状态有更新时,可以通过飞书审批的Bot告知用户。当然开发者也可以利用开放平台的能力自建一个全新的Bot,用来推送审批相关信息。 +`, + Request: "POST https://www.feishu.cn/approval/openapi/v1/message/send", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDNyYjL4QjM24CO0IjN", + FuncName: "MessageSend", + }, + { + Name: "更新审批Bot消息", + Description: `此接口可以根据审批bot消息id及相应状态,更新相应的审批bot消息。例如,给用户推送了审批待办消息,当用户处理该消息后,可以将之前推送的Bot消息更新为已审批。 +`, + Request: "POST https://www.feishu.cn/approval/openapi/v1/message/update", + See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNyYjLwYjM24CM2IjN", + FuncName: "MessageUpdate", }, { Name: "创建审批定义", @@ -691,7 +901,7 @@ var apiConfig2 = []ApiGroup{ `, Request: "POST https://www.feishu.cn/approval/openapi/v2/approval/create", See: "https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUzNyYjL1cjM24SN3IjN", - FuncName: "Create", + FuncName: "ApprovalCreate", }, { Name: "审批实例抄送", @@ -726,7 +936,7 @@ var apiConfig2 = []ApiGroup{ }, { Name: `会议室`, - Package: `capabilities/meeting`, + Package: `capabilities/meeting_room`, Apis: []Api{ { diff --git a/cmd/build.go b/cmd/build.go index 031f1bf..3dbaba2 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -23,6 +23,8 @@ import ( "path" "strings" + "github.com/fastwego/feishu" + "github.com/iancoleman/strcase" ) @@ -30,8 +32,8 @@ func main() { var pkgFlag string flag.StringVar(&pkgFlag, "package", "user", "") flag.Parse() - for _, group := range apiConfig { - if group.Package == "oauth" { // 单独处理 oauth 模块 + for _, group := range apiConfig2 { + if group.Package == "authen" { // 单独处理 authen 模块 continue } @@ -70,11 +72,17 @@ func build(group ApiGroup) { var exampleFuncs []string for _, api := range group.Apis { + tpl := postFuncTpl _FUNC_NAME_ := "" _GET_PARAMS_ := "" _GET_SUFFIX_PARAMS_ := "" _PAYLOAD_ := "" + _SERVERURL_ := "feishu.FeishuServerUrl" + if strings.Contains(api.Request, feishu.FeishuServerUrl2) { + _SERVERURL_ = "feishu.FeishuServerUrl2" + } + switch { case strings.Contains(api.Request, "GET http"): tpl = getFuncTpl @@ -82,6 +90,10 @@ func build(group ApiGroup) { tpl = deleteFuncTpl case strings.Contains(api.Request, "POST http"): tpl = postFuncTpl + case strings.Contains(api.Request, "PUT http"): + tpl = putFuncTpl + case strings.Contains(api.Request, "PATCH http"): + tpl = patchFuncTpl } if len(api.GetParams) > 0 || len(api.PathParams) > 0 { _GET_PARAMS_ = `, params url.Values` @@ -94,6 +106,7 @@ func build(group ApiGroup) { } split := strings.Split(api.Request, " ") + _METHOD_ := split[0] parseUrl, _ := url.Parse(split[1]) if api.FuncName == "" { @@ -104,11 +117,11 @@ func build(group ApiGroup) { _APIVARNAME_ := "api" + _FUNC_NAME_ _HEADER_ := tenantAccessTokenTpl - _HEADERPARAM_ := "" + _ACCESSTOKENPARAM_ := "" if api.AccessToken == "app" { _HEADER_ = appAccessTokenTpl } else if api.AccessToken == "user" { - _HEADERPARAM_ = ", header http.Header" + _ACCESSTOKENPARAM_ = ", accessToken string" _HEADER_ = userAccessTokenTpl } @@ -122,8 +135,17 @@ func build(group ApiGroup) { _APIVARNAME_ = "api" } + isUploadApi := false + if (group.Package == "message" && api.FuncName == "ImagePut") || (group.Package == "capabilities/approval" && api.FuncName == "Upload") { + file, err := ioutil.ReadFile("tpl/" + api.FuncName + ".tpl") + if err != nil { + continue + } + tpl = commentTpl + string(file) + isUploadApi = true + } tpl = strings.ReplaceAll(tpl, "_HEADER_", _HEADER_) - tpl = strings.ReplaceAll(tpl, "_HEADERPARAM_", _HEADERPARAM_) + tpl = strings.ReplaceAll(tpl, "_ACCESSTOKENPARAM_", _ACCESSTOKENPARAM_) tpl = strings.ReplaceAll(tpl, "_TITLE_", api.Name) tpl = strings.ReplaceAll(tpl, "_DESCRIPTION_", api.Description) tpl = strings.ReplaceAll(tpl, "_REQUEST_", api.Request) @@ -134,6 +156,7 @@ func build(group ApiGroup) { tpl = strings.ReplaceAll(tpl, "_PAYLOAD_", _PAYLOAD_) tpl = strings.ReplaceAll(tpl, "_PATH_PARAMS_", _PATH_PARAMS_) tpl = strings.ReplaceAll(tpl, "_APIVARNAME_", _APIVARNAME_) + tpl = strings.ReplaceAll(tpl, "_SERVERURL_", _SERVERURL_) funcs = append(funcs, tpl) @@ -142,28 +165,29 @@ func build(group ApiGroup) { consts = append(consts, tpl) + if isUploadApi { // 不用 test case + continue + } + // TestFunc _TEST_ARGS_STRUCT_ := "" - _EXAMPLE_HEADER_STMT_ := "" - _HEADERINIT_ := "" + _ACCESSTOKENINIT_ := "" switch { case strings.Contains(api.Request, "GET http") || strings.Contains(api.Request, "DELETE http"): _TEST_ARGS_STRUCT_ = `ctx *feishu.App, ` + _GET_PARAMS_ if api.AccessToken == "user" { - _TEST_ARGS_STRUCT_ += `, header http.Header` - _EXAMPLE_HEADER_STMT_ = `header := http.Header{}` - _HEADERINIT_ = `, header: http.Header{}` + _TEST_ARGS_STRUCT_ += `, accessToken string` + _ACCESSTOKENINIT_ = `, accessToken: "USER_ACCESS_TOKEN"` } - case strings.Contains(api.Request, "POST http"): + case strings.Contains(api.Request, "POST http") || strings.Contains(api.Request, "PUT http") || strings.Contains(api.Request, "PATCH http"): _TEST_ARGS_STRUCT_ = `ctx *feishu.App, payload []byte` if _GET_PARAMS_ != "" { _TEST_ARGS_STRUCT_ += `,` + _GET_PARAMS_ } if api.AccessToken == "user" { - _TEST_ARGS_STRUCT_ += `, header http.Header` - _EXAMPLE_HEADER_STMT_ = `header := http.Header{}` - _HEADERINIT_ = `, header: http.Header{}` + _TEST_ARGS_STRUCT_ += `, accessToken string` + _ACCESSTOKENINIT_ = `, accessToken: "USER_ACCESS_TOKEN"` } } _TEST_ARGS_STRUCT_ = strings.ReplaceAll(_TEST_ARGS_STRUCT_, ",", "\n") @@ -199,7 +223,8 @@ func build(group ApiGroup) { tpl = strings.ReplaceAll(testFuncTpl, "_FUNC_NAME_", _FUNC_NAME_) tpl = strings.ReplaceAll(tpl, "_TEST_ARGS_STRUCT_", _TEST_ARGS_STRUCT_) tpl = strings.ReplaceAll(tpl, "_TEST_FUNC_SIGNATURE_", _TEST_FUNC_SIGNATURE_) - tpl = strings.ReplaceAll(tpl, "_HEADERINIT_", _HEADERINIT_) + tpl = strings.ReplaceAll(tpl, "_ACCESSTOKENINIT_", _ACCESSTOKENINIT_) + tpl = strings.ReplaceAll(tpl, "_METHOD_", _METHOD_) testFuncs = append(testFuncs, tpl) //Example @@ -208,7 +233,6 @@ func build(group ApiGroup) { tpl = strings.ReplaceAll(tpl, "_PACKAGE_", path.Base(group.Package)) tpl = strings.ReplaceAll(tpl, "_TEST_FUNC_SIGNATURE_", strings.ReplaceAll(_TEST_FUNC_SIGNATURE_, "tt.args.", "")) tpl = strings.ReplaceAll(tpl, "_EXAMPLE_ARGS_STMT_", _EXAMPLE_ARGS_STMT_) - tpl = strings.ReplaceAll(tpl, "_EXAMPLE_HEADER_STMT_", _EXAMPLE_HEADER_STMT_) exampleFuncs = append(exampleFuncs, tpl) } @@ -243,26 +267,40 @@ See: _SEE_ _REQUEST_ */` var postFuncTpl = commentTpl + ` -func _FUNC_NAME_(ctx *feishu.App, payload []byte_GET_PARAMS__HEADERPARAM_) (resp []byte, err error) { +func _FUNC_NAME_(ctx *feishu.App, payload []byte_GET_PARAMS__ACCESSTOKENPARAM_) (resp []byte, err error) { _PATH_PARAMS_ _HEADER_ - return ctx.Client.HTTPPost(_APIVARNAME__GET_SUFFIX_PARAMS_, bytes.NewReader(payload), header) + return ctx.Client.HTTPPost(_SERVERURL_+_APIVARNAME__GET_SUFFIX_PARAMS_, bytes.NewReader(payload), header) } ` var getFuncTpl = commentTpl + ` -func _FUNC_NAME_(ctx *feishu.App_GET_PARAMS__HEADERPARAM_) (resp []byte, err error) { +func _FUNC_NAME_(ctx *feishu.App_GET_PARAMS__ACCESSTOKENPARAM_) (resp []byte, err error) { _PATH_PARAMS_ _HEADER_ - return ctx.Client.HTTPGet(_APIVARNAME__GET_SUFFIX_PARAMS_,header) + return ctx.Client.HTTPGet(_SERVERURL_+_APIVARNAME__GET_SUFFIX_PARAMS_,header) } ` var deleteFuncTpl = commentTpl + ` -func _FUNC_NAME_(ctx *feishu.App_GET_PARAMS__HEADERPARAM_) (resp []byte, err error) { +func _FUNC_NAME_(ctx *feishu.App_GET_PARAMS__ACCESSTOKENPARAM_) (resp []byte, err error) { _PATH_PARAMS_ _HEADER_ - return ctx.Client.HTTPDelete(_APIVARNAME__GET_SUFFIX_PARAMS_,header) + return ctx.Client.HTTPDelete(_SERVERURL_+_APIVARNAME__GET_SUFFIX_PARAMS_,header) +} +` +var putFuncTpl = commentTpl + ` +func _FUNC_NAME_(ctx *feishu.App, payload []byte_GET_PARAMS__ACCESSTOKENPARAM_) (resp []byte, err error) { + _PATH_PARAMS_ + _HEADER_ + return ctx.Client.HTTPPut(_SERVERURL_+_APIVARNAME__GET_SUFFIX_PARAMS_, bytes.NewReader(payload), header) +} +` +var patchFuncTpl = commentTpl + ` +func _FUNC_NAME_(ctx *feishu.App, payload []byte_GET_PARAMS__ACCESSTOKENPARAM_) (resp []byte, err error) { + _PATH_PARAMS_ + _HEADER_ + return ctx.Client.HTTPPatch(_SERVERURL_+_APIVARNAME__GET_SUFFIX_PARAMS_, bytes.NewReader(payload), header) } ` var tenantAccessTokenTpl = ` @@ -272,7 +310,7 @@ var tenantAccessTokenTpl = ` } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") ` var appAccessTokenTpl = ` @@ -282,11 +320,13 @@ var appAccessTokenTpl = ` } header := http.Header{} header.Set("Authorization", "Bearer "+accessToken) - header.Set("Content-appType", "application/json") + header.Set("Content-Type", "application/json") ` var userAccessTokenTpl = ` - header.Set("Content-appType", "application/json") + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", "application/json") ` var fieldTpl = ` @@ -321,9 +361,9 @@ func Test_FUNC_NAME_(t *testing.T) { "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), } var resp []byte - test.MockSvrHandler.HandleFunc(api_FUNC_NAME_, func(w http.ResponseWriter, r *http.Request) { + test.MockRouter.HandleFunc(api_FUNC_NAME_, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(resp)) - }) + }).Methods("_METHOD_") type args struct { _TEST_ARGS_STRUCT_ @@ -334,7 +374,7 @@ func Test_FUNC_NAME_(t *testing.T) { wantResp []byte wantErr bool }{ - {name: "case1", args: args{ctx: test.MockApp_HEADERINIT_}, wantResp: mockResp["case1"], wantErr: false}, + {name: "case1", args: args{ctx: test.MockApp_ACCESSTOKENINIT_}, wantResp: mockResp["case1"], wantErr: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -361,7 +401,6 @@ func Example_FUNC_NAME_() { var ctx *feishu.App _EXAMPLE_ARGS_STMT_ - _EXAMPLE_HEADER_STMT_ resp, err := _PACKAGE_._FUNC_NAME_(_TEST_FUNC_SIGNATURE_) fmt.Println(resp, err) diff --git a/cmd/tpl/ImagePut.tpl b/cmd/tpl/ImagePut.tpl new file mode 100644 index 0000000..7a9580c --- /dev/null +++ b/cmd/tpl/ImagePut.tpl @@ -0,0 +1,40 @@ + +func ImagePut(ctx *feishu.App, image string, params url.Values) (resp []byte, err error) { + + r, w := io.Pipe() + m := multipart.NewWriter(w) + go func() { + defer w.Close() + defer m.Close() + + part, err := m.CreateFormFile("image", path.Base(image)) + if err != nil { + return + } + file, err := os.Open(image) + if err != nil { + return + } + defer file.Close() + if _, err = io.Copy(part, file); err != nil { + return + } + + // field + err = m.WriteField("image_type", params.Get("image_type")) + if err != nil { + return + } + + }() + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", m.FormDataContentType()) + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl+apiImagePut, r, header) +} \ No newline at end of file diff --git a/cmd/tpl/Upload.tpl b/cmd/tpl/Upload.tpl new file mode 100644 index 0000000..c8507e4 --- /dev/null +++ b/cmd/tpl/Upload.tpl @@ -0,0 +1,45 @@ + +func Upload(ctx *feishu.App, content string, params url.Values) (resp []byte, err error) { + + r, w := io.Pipe() + m := multipart.NewWriter(w) + go func() { + defer w.Close() + defer m.Close() + + part, err := m.CreateFormFile("content", path.Base(content)) + if err != nil { + return + } + file, err := os.Open(content) + if err != nil { + return + } + defer file.Close() + if _, err = io.Copy(part, file); err != nil { + return + } + + // field + err = m.WriteField("type", params.Get("type")) + if err != nil { + return + } + + err = m.WriteField("name", path.Base(content)) + if err != nil { + return + } + + }() + + accessToken, err := ctx.GetTenantAccessTokenHandler() + if err != nil { + return + } + header := http.Header{} + header.Set("Authorization", "Bearer "+accessToken) + header.Set("Content-Type", m.FormDataContentType()) + + return ctx.Client.HTTPPost(feishu.FeishuServerUrl2+apiUpload, r, header) +} \ No newline at end of file diff --git a/doc/apilist.md b/doc/apilist.md index ab76913..338a2c5 100644 --- a/doc/apilist.md +++ b/doc/apilist.md @@ -1,3 +1,14 @@ +- 身份认证(authen) + - [获取用户授权跳转链接](https://open.feishu.cn/document/ukTMukTMukTM/ukzN4UjL5cDO14SO3gTN) + - [GetRedirectUri (/open-apis/authen/v1/index)](https://pkg.go.dev/github.com/fastwego/feishu/apis/authen?tab=doc#GetRedirectUri) + - [获取登录用户身份](https://open.feishu.cn/document/ukTMukTMukTM/uEDO4UjLxgDO14SM4gTN) + - [GetAccessToken (/open-apis/authen/v1/access_token)](https://pkg.go.dev/github.com/fastwego/feishu/apis/authen?tab=doc#GetAccessToken) + - [刷新access_token](https://open.feishu.cn/document/ukTMukTMukTM/uQDO4UjL0gDO14CN4gTN) + - [RefreshAccessToken (/open-apis/authen/v1/refresh_access_token)](https://pkg.go.dev/github.com/fastwego/feishu/apis/authen?tab=doc#RefreshAccessToken) + - [获取用户信息(身份验证)](https://open.feishu.cn/document/ukTMukTMukTM/uIDO4UjLygDO14iM4gTN) + - [GetUserInfo (/open-apis/authen/v1/user_info)](https://pkg.go.dev/github.com/fastwego/feishu/apis/authen?tab=doc#GetUserInfo) + - [小程序登录/code2session](https://open.feishu.cn/document/uYjL24iN/ukjM04SOyQjL5IDN) + - [Code2Session (/open-apis/mina/v2/tokenLoginValidate)](https://pkg.go.dev/github.com/fastwego/feishu/apis/authen?tab=doc#Code2Session) - 用户管理(contact/user) - [批量获取用户信息](https://open.feishu.cn/document/ukTMukTMukTM/uIzNz4iM3MjLyczM) - [BatchGet (/open-apis/contact/v1/user/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/user?tab=doc#BatchGet) @@ -23,17 +34,17 @@ - [Search (/open-apis/search/v1/user)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/user?tab=doc#Search) - 部门管理(contact/department) - [获取部门详情](https://open.feishu.cn/document/ukTMukTMukTM/uAzNz4CM3MjLwczM) - - [DepartmentInfoGet (/open-apis/contact/v1/department/info/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#DepartmentInfoGet) + - [InfoGet (/open-apis/contact/v1/department/info/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#InfoGet) - [获取子部门列表](https://open.feishu.cn/document/ukTMukTMukTM/ugzN3QjL4czN04CO3cDN) - - [DepartmentSimpleList (/open-apis/contact/v1/department/simple/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#DepartmentSimpleList) + - [SimpleList (/open-apis/contact/v1/department/simple/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#SimpleList) - [批量获取部门详情](https://open.feishu.cn/document/ukTMukTMukTM/uczN3QjL3czN04yN3cDN) - - [DepartmentDetailBatchGet (/open-apis/contact/v1/department/detail/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#DepartmentDetailBatchGet) + - [DetailBatchGet (/open-apis/contact/v1/department/detail/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#DetailBatchGet) - [新增部门](https://open.feishu.cn/document/ukTMukTMukTM/uYzNz4iN3MjL2czM) - - [DepartmentAdd (/open-apis/contact/v1/department/add)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#DepartmentAdd) + - [Add (/open-apis/contact/v1/department/add)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#Add) - [删除部门](https://open.feishu.cn/document/ukTMukTMukTM/ugzNz4CO3MjL4czM) - - [DepartmentDelete (/open-apis/contact/v1/department/delete)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#DepartmentDelete) + - [Delete (/open-apis/contact/v1/department/delete)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#Delete) - [更新部门信息](https://open.feishu.cn/document/ukTMukTMukTM/uczNz4yN3MjL3czM) - - [DepartmentUpdate (/open-apis/contact/v1/department/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#DepartmentUpdate) + - [Update (/open-apis/contact/v1/department/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/department?tab=doc#Update) - 异步批量接口(contact/async_batch) - [批量新增部门](https://open.feishu.cn/document/ukTMukTMukTM/uMDOwUjLzgDM14yM4ATN) - [DepartmentBatchAdd (/open-apis/contact/v2/department/batch_add)](https://pkg.go.dev/github.com/fastwego/feishu/apis/contact/async_batch?tab=doc#DepartmentBatchAdd) @@ -51,26 +62,28 @@ - [Members (/open-apis/chat/v4/members)](https://pkg.go.dev/github.com/fastwego/feishu/apis/user_group?tab=doc#Members) - [搜索用户所在的群列表](https://open.feishu.cn/document/ukTMukTMukTM/uUTOyUjL1kjM14SN5ITN) - [Search (/open-apis/chat/v4/search)](https://pkg.go.dev/github.com/fastwego/feishu/apis/user_group?tab=doc#Search) -- 应用信息/应用管理(appinfo/app_manage) +- 应用信息/应用管理(app/app_manage) - [校验应用管理员](https://open.feishu.cn/document/ukTMukTMukTM/uITN1EjLyUTNx4iM1UTM) - - [IsUserAdmin (/open-apis/application/v3/is_user_admin)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/app_manage?tab=doc#IsUserAdmin) + - [IsUserAdmin (/open-apis/application/v3/is_user_admin)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_manage?tab=doc#IsUserAdmin) - [获取应用管理员管理范围](https://open.feishu.cn/document/ukTMukTMukTM/uMzN3QjLzczN04yM3cDN) - - [AdminScopeGet (/open-apis/contact/v1/user/admin_scope/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/app_manage?tab=doc#AdminScopeGet) + - [AdminScopeGet (/open-apis/contact/v1/user/admin_scope/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_manage?tab=doc#AdminScopeGet) - [获取应用在企业内的可用范围](https://open.feishu.cn/document/ukTMukTMukTM/uIjM3UjLyIzN14iMycTN) - - [AppVisibility (/open-apis/application/v2/app/visibility)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/app_manage?tab=doc#AppVisibility) + - [AppVisibility (/open-apis/application/v2/app/visibility)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_manage?tab=doc#AppVisibility) - [获取用户可用的应用](https://open.feishu.cn/document/ukTMukTMukTM/uMjM3UjLzIzN14yMycTN) - - [VisibleApps (/open-apis/application/v1/user/visible_apps)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/app_manage?tab=doc#VisibleApps) + - [VisibleApps (/open-apis/application/v1/user/visible_apps)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_manage?tab=doc#VisibleApps) - [获取企业安装的应用](https://open.feishu.cn/document/ukTMukTMukTM/uYDN3UjL2QzN14iN0cTN) - - [AppList (/open-apis/application/v3/app/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/app_manage?tab=doc#AppList) + - [AppList (/open-apis/application/v3/app/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_manage?tab=doc#AppList) - [更新应用可用范围](https://open.feishu.cn/document/ukTMukTMukTM/ucDN3UjL3QzN14yN0cTN) - - [UpdateVisibility (/open-apis/application/v3/app/update_visibility)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/app_manage?tab=doc#UpdateVisibility) + - [UpdateVisibility (/open-apis/application/v3/app/update_visibility)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_manage?tab=doc#UpdateVisibility) - [查询应用管理员列表](https://open.feishu.cn/document/ukTMukTMukTM/ucDOwYjL3gDM24yN4AjN) - - [AppAdminUserList (/open-apis/user/v4/app_admin_user/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/app_manage?tab=doc#AppAdminUserList) -- 应用信息/应用商店(appinfo/appstore) + - [AppAdminUserList (/open-apis/user/v4/app_admin_user/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_manage?tab=doc#AppAdminUserList) +- 应用信息/应用商店(app/app_store) + - [查询用户是否在应用开通范围](https://open.feishu.cn/document/ukTMukTMukTM/uATNwUjLwUDM14CM1ATN) + - [CheckUser (/open-apis/pay/v1/paid_scope/check_user)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_store?tab=doc#CheckUser) - [查询租户购买的付费方案](https://open.feishu.cn/document/ukTMukTMukTM/uETNwUjLxUDM14SM1ATN) - - [OrderList (/open-apis/pay/v1/order/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/appstore?tab=doc#OrderList) + - [OrderList (/open-apis/pay/v1/order/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_store?tab=doc#OrderList) - [查询订单详情](https://open.feishu.cn/document/ukTMukTMukTM/uITNwUjLyUDM14iM1ATN) - - [OrderGet (/open-apis/pay/v1/order/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/appinfo/appstore?tab=doc#OrderGet) + - [OrderGet (/open-apis/pay/v1/order/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/app/app_store?tab=doc#OrderGet) - 机器人/群信息和群管理(bot/group_manage) - [创建群](https://open.feishu.cn/document/ukTMukTMukTM/ukDO5QjL5gTO04SO4kDN) - [ChatCreate (/open-apis/chat/v4/create/)](https://pkg.go.dev/github.com/fastwego/feishu/apis/bot/group_manage?tab=doc#ChatCreate) @@ -96,7 +109,7 @@ - 消息(message) - [批量发送消息](https://open.feishu.cn/document/ukTMukTMukTM/ucDO1EjL3gTNx4yN4UTM) - [BatchSend (/open-apis/message/v4/batch_send/)](https://pkg.go.dev/github.com/fastwego/feishu/apis/message?tab=doc#BatchSend) - - [发送文本消息](https://open.feishu.cn/document/ukTMukTMukTM/uUjNz4SN2MjL1YzM) + - [发送消息](https://open.feishu.cn/document/ukTMukTMukTM/uUjNz4SN2MjL1YzM) - [Send (/open-apis/message/v4/send/)](https://pkg.go.dev/github.com/fastwego/feishu/apis/message?tab=doc#Send) - [查询消息已读状态](https://open.feishu.cn/document/ukTMukTMukTM/ukTM2UjL5EjN14SOxYTN) - [ReadInfo (/open-apis/message/v4/read_info/)](https://pkg.go.dev/github.com/fastwego/feishu/apis/message?tab=doc#ReadInfo) @@ -117,144 +130,180 @@ - [CreateCalendars (/open-apis/calendar/v3/calendars)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#CreateCalendars) - [删除日历](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUTM14SNxUjL1ETN) - [DeleteCalendarById (/open-apis/calendar/v3/calendars/:calendarId)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#DeleteCalendarById) + - [更新日历](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTM14iNxUjL2ETN) + - [UpdateCalendarById (/open-apis/calendar/v3/calendars/:calendarId)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#UpdateCalendarById) - [获取日程](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucTM14yNxUjL3ETN) - [GetEventById (/open-apis/calendar/v3/calendars/:calendarId/events/:eventId)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#GetEventById) - [创建日程](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugTM14COxUjL4ETN) - [CreateEvent (/open-apis/calendar/v3/calendars/:calendarId/events)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#CreateEvent) + - [获取日程列表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTM14SOxUjL5ETN) + - [GetEvents (/open-apis/calendar/v3/calendars/:calendarId/events)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#GetEvents) + - [删除日程](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjM14CMyUjLwITN) + - [DeleteEventById (/open-apis/calendar/v3/calendars/:calendarId/events/:eventId)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#DeleteEventById) + - [更新日程](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjM14SMyUjLxITN) + - [UpdateEventById (/open-apis/calendar/v3/calendars/:calendarId/events/:eventId)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#UpdateEventById) - [邀请/移除日程参与者](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIjM14iMyUjLyITN) - [Attendees (/open-apis/calendar/v3/calendars/:calendarId/events/:eventId/attendees)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#Attendees) - [获取访问控制列表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjM14yMyUjLzITN) - - [Acl (/open-apis/calendar/v3/calendars/:calendarId/acl)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#Acl) + - [GetAcl (/open-apis/calendar/v3/calendars/:calendarId/acl)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#GetAcl) + - [创建访问控制](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQjM14CNyUjL0ITN) + - [CreateAcl (/open-apis/calendar/v3/calendars/:calendarId/acl)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#CreateAcl) - [删除访问控制](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUjM14SNyUjL1ITN) - - [DeleteAclByRuleId (/open-apis/calendar/v3/calendars/:calendarId/acl/:ruleId)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#DeleteAclByRuleId) + - [DeleteAcl (/open-apis/calendar/v3/calendars/:calendarId/acl/:ruleId)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#DeleteAcl) - [查询日历的忙闲状态](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYjM14iNyUjL2ITN) - [FreeBusyQuery (/open-apis/calendar/v3/freebusy/query)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#FreeBusyQuery) - [查询公共日历](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukDMwYjL5ADM24SOwAjN) - [SharedCalendarQuery (/open-apis/calendar/v3/shared_calendar_list/shared_calendar/query)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#SharedCalendarQuery) - [获取公共日历日程列表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIzNwYjLycDM24iM3AjN) - [SharedCalendarEvents (/open-apis/calendar/v3/shared/calendars/:calendarId/events)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/calendar?tab=doc#SharedCalendarEvents) -- 云文档(capabilities/document) +- 云文档/folder(capabilities/document/folder) - [新建文件夹](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTNzUjL5UzM14SO1MTN) - - [CreateFolder (/open-apis/drive/explorer/v2/folder/:folderToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#CreateFolder) + - [Create (/open-apis/drive/explorer/v2/folder/:folderToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/folder?tab=doc#Create) - [获取文件夹元信息](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNzUjLwYzM14CM2MTN) - - [RootFolderMeta (/open-apis/drive/explorer/v2/root_folder/meta)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#RootFolderMeta) + - [Meta (/open-apis/drive/explorer/v2/folder/:folderToken/meta)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/folder?tab=doc#Meta) + - [获取root folder(我的空间) meta](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNzUjLwYzM14CM2MTN) + - [RootFolderMeta (/open-apis/drive/explorer/v2/root_folder/meta)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/folder?tab=doc#RootFolderMeta) - [获取文件夹下的文档清单](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjNzUjLxYzM14SM2MTN) - - [FolderChildren (/open-apis/drive/explorer/v2/folder/:folderToken/children)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#FolderChildren) + - [Children (/open-apis/drive/explorer/v2/folder/:folderToken/children)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/folder?tab=doc#Children) +- 云文档/file(capabilities/document/file) - [新建文档](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQTNzUjL0UzM14CN1MTN) - - [CreateFile (/open-apis/drive/explorer/v2/file/:folderToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#CreateFile) + - [Create (/open-apis/drive/explorer/v2/file/:folderToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/file?tab=doc#Create) - [复制文档](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTNzUjL2UzM14iN1MTN) - - [CopyFile (/open-apis/drive/explorer/v2/file/copy/files/:fileToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#CopyFile) - - [删除文档](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATM2UjLwEjN14CMxYTN) - - [DeleteFile (/open-apis/drive/explorer/v2/file/spreadsheets/:spreadsheetToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#DeleteFile) + - [Copy (/open-apis/drive/explorer/v2/file/copy/files/:fileToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/file?tab=doc#Copy) + - [删除 Doc](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATM2UjLwEjN14CMxYTN) + - [DeleteDoc (/open-apis/drive/explorer/v2/file/docs/:docToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/file?tab=doc#DeleteDoc) +- 云文档/permission(capabilities/document/permission) - [增加权限](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMzNzUjLzczM14yM3MTN) - - [PermissionMemberCreate (/open-apis/drive/permission/member/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#PermissionMemberCreate) + - [MemberCreate (/open-apis/drive/permission/member/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/permission?tab=doc#MemberCreate) - [转移拥有者](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQzNzUjL0czM14CN3MTN) - - [PermissionMemberTransfer (/open-apis/drive/permission/member/transfer)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#PermissionMemberTransfer) + - [MemberTransfer (/open-apis/drive/permission/member/transfer)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/permission?tab=doc#MemberTransfer) - [更新文档公共设置](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTM3UjL5EzN14SOxcTN) - - [PermissionPublicUpdate (/open-apis/drive/permission/public/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#PermissionPublicUpdate) + - [PublicUpdate (/open-apis/drive/permission/public/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/permission?tab=doc#PublicUpdate) - [获取协作者列表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATN3UjLwUzN14CM1cTN) - - [PermissionMemberList (/open-apis/drive/permission/member/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#PermissionMemberList) + - [MemberList (/open-apis/drive/permission/member/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/permission?tab=doc#MemberList) - [移除协作者权限](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTN3UjL2UzN14iN1cTN) - - [PermissionMemberDelete (/open-apis/drive/permission/member/delete)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#PermissionMemberDelete) + - [MemberDelete (/open-apis/drive/permission/member/delete)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/permission?tab=doc#MemberDelete) - [更新协作者权限](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucTN3UjL3UzN14yN1cTN) - - [PermissionMemberUpdate (/open-apis/drive/permission/member/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#PermissionMemberUpdate) + - [MemberUpdate (/open-apis/drive/permission/member/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/permission?tab=doc#MemberUpdate) - [判断协作者是否有某权限](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYzN3UjL2czN14iN3cTN) - - [PermissionMemberPermitted (/open-apis/drive/permission/member/permitted)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#PermissionMemberPermitted) + - [MemberPermitted (/open-apis/drive/permission/member/permitted)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/permission?tab=doc#MemberPermitted) +- 云文档/docs(capabilities/document/docs) - [获取文档文本内容](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukzNzUjL5czM14SO3MTN) - - [RawContent (/open-apis/doc/v2/:docToken/raw_content)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#RawContent) + - [RawContent (/open-apis/doc/v2/:docToken/raw_content)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/docs?tab=doc#RawContent) - [获取sheet@doc的元数据](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uADOzUjLwgzM14CM4MTN) - - [SheetMeta (/open-apis/doc/v2/:docToken/sheet_meta)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SheetMeta) + - [SheetMeta (/open-apis/doc/v2/:docToken/sheet_meta)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/docs?tab=doc#SheetMeta) - [获取文档元信息](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uczN3UjL3czN14yN3cTN) - - [DocMeta (/open-apis/doc/v2/meta/:docToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#DocMeta) + - [DocMeta (/open-apis/doc/v2/meta/:docToken)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/docs?tab=doc#DocMeta) +- 云文档/sheets(capabilities/document/sheets) - [获取表格元数据](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uETMzUjLxEzM14SMxMTN) - - [SpreadSheetsMetainfo (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/metainfo)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsMetainfo) - - [操作子表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTMzUjL2EzM14iNxMTN) - - [SheetsBatchUpdate (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/sheets_batch_update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SheetsBatchUpdate) + - [MetaInfo (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/metainfo)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#MetaInfo) + - [更新表格属性](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucTMzUjL3EzM14yNxMTN) + - [UpdateProperties (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/properties)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#UpdateProperties) + - [操作子表/更新子表属性](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYTMzUjL2EzM14iNxMTN) + - [BatchUpdate (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/sheets_batch_update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#BatchUpdate) - [插入数据](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIjMzUjLyIzM14iMyMTN) - - [SpreadSheetsValuesPrepend (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_prepend)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsValuesPrepend) + - [ValuesPrepend (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_prepend)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#ValuesPrepend) - [追加数据](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjMzUjLzIzM14yMyMTN) - - [SpreadSheetsValuesAppend (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_append)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsValuesAppend) + - [ValuesAppend (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_append)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#ValuesAppend) - [插入行列](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQjMzUjL0IzM14CNyMTN) - - [SpreadSheetsInsertDimensionRange (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/insert_dimension_range)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsInsertDimensionRange) + - [InsertDimensionRange (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/insert_dimension_range)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#InsertDimensionRange) - [增加行列](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUjMzUjL1IzM14SNyMTN) - - [SpreadSheetsDimensionRange (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsDimensionRange) + - [CreateDimensionRange (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#CreateDimensionRange) + - [更新行列](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYjMzUjL2IzM14iNyMTN) + - [UpdateDimensionRange (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#UpdateDimensionRange) + - [删除行列](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucjMzUjL3IzM14yNyMTN) + - [DeleteDimensionRange (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/dimension_range)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#DeleteDimensionRange) + - [设置单元格样式](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukjMzUjL5IzM14SOyMTN) + - [UpdateStyle (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/style)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#UpdateStyle) + - [批量设置单元格样式](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAzMzUjLwMzM14CMzMTN) + - [BatchUpdateStyle (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/styles_batch_update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#BatchUpdateStyle) - [增加锁定单元格](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDNzUjL4QzM14CO0MTN) - - [SpreadSheetsProtectedDimension (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/protected_dimension)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsProtectedDimension) + - [ProtectedDimension (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/protected_dimension)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#ProtectedDimension) - [合并单元格](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukDNzUjL5QzM14SO0MTN) - - [SpreadSheetsMergeCells (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/merge_cells)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsMergeCells) + - [MergeCells (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/merge_cells)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#MergeCells) - [拆分单元格](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATNzUjLwUzM14CM1MTN) - - [SpreadSheetsUnmergeCells (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/unmerge_cells)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsUnmergeCells) + - [UnmergeCells (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/unmerge_cells)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#UnmergeCells) - [读取单个范围](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugTMzUjL4EzM14COxMTN) - - [SpreadSheetsRange (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values/:range)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsRange) + - [Range (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values/:range)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#Range) + - [向单个范围写入数据](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjMzUjLwIzM14CMyMTN) + - [Values (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#Values) - [读取多个范围](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukTMzUjL5EzM14SOxMTN) - - [SpreadSheetsValuesBatchGet (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsValuesBatchGet) + - [ValuesBatchGet (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#ValuesBatchGet) - [向多个范围写入数据](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEjMzUjLxIzM14SMyMTN) - - [SpreadSheetsValuesBatchUpdate (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SpreadSheetsValuesBatchUpdate) + - [ValuesBatchUpdate (/open-apis/sheet/v2/spreadsheets/:spreadsheetToken/values_batch_update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/sheets?tab=doc#ValuesBatchUpdate) +- 云文档/platform(capabilities/document/platform) - [获取元数据](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMjN3UjLzYzN14yM2cTN) - - [DocsMeta (/open-apis/suite/docs-api/meta)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#DocsMeta) + - [DocsMeta (/open-apis/suite/docs-api/meta)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/platform?tab=doc#DocsMeta) - [文档搜索](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDM4UjL4ADO14COwgTN) - - [SearchObject (/open-apis/suite/docs-api/search/object)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#SearchObject) + - [SearchObject (/open-apis/suite/docs-api/search/object)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/platform?tab=doc#SearchObject) +- 云文档/评论(capabilities/document/comment) - [添加全文评论](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucDN4UjL3QDO14yN0gTN) - - [CommentAddWhole (/open-apis/comment/add_whole)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document?tab=doc#CommentAddWhole) -- 审批(capabilities/approve) + - [AddWhole (/open-apis/comment/add_whole)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/document/comment?tab=doc#AddWhole) +- 审批(capabilities/approval) - [查看审批定义](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uADNyUjLwQjM14CM0ITN) - - [Get (/approval/openapi/v2/approval/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Get) + - [Get (/approval/openapi/v2/approval/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#Get) - [批量获取审批实例ID](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQDOyUjL0gjM14CN4ITN) - - [InstanceList (/approval/openapi/v2/instance/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#InstanceList) + - [InstanceList (/approval/openapi/v2/instance/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#InstanceList) - [获取单个审批实例详情](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEDNyUjLxQjM14SM0ITN) - - [InstanceGet (/approval/openapi/v2/instance/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#InstanceGet) + - [InstanceGet (/approval/openapi/v2/instance/get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#InstanceGet) - [创建审批实例](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIDNyUjLyQjM14iM0ITN) - - [InstanceCreate (/approval/openapi/v2/instance/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#InstanceCreate) + - [InstanceCreate (/approval/openapi/v2/instance/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#InstanceCreate) - [审批任务同意](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMDNyUjLzQjM14yM0ITN) - - [Approve (/approval/openapi/v2/instance/approve)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Approve) + - [Approve (/approval/openapi/v2/instance/approve)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#Approve) - [审批任务拒绝](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQDNyUjL0QjM14CN0ITN) - - [Reject (/approval/openapi/v2/instance/reject)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Reject) + - [Reject (/approval/openapi/v2/instance/reject)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#Reject) - [审批任务转交](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUDNyUjL1QjM14SN0ITN) - - [Transfer (/approval/openapi/v2/instance/transfer)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Transfer) + - [Transfer (/approval/openapi/v2/instance/transfer)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#Transfer) - [审批实例撤回](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYDNyUjL2QjM14iN0ITN) - - [Cancel (/approval/openapi/v2/instance/cancel)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Cancel) + - [Cancel (/approval/openapi/v2/instance/cancel)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#Cancel) - [上传文件](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUDOyUjL1gjM14SN4ITN) - - [Upload (/approval/openapi/v2/file/upload)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Upload) - - [三方审批实例同步](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uczM3UjL3MzN14yNzcTN) - - [ExternalInstanceCreate (/approval/openapi/v2/external/instance/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#ExternalInstanceCreate) + - [Upload (/approval/openapi/v2/file/upload)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#Upload) + - [三方审批定义创建/同步](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIDNyYjLyQjM24iM0IjN) + - [ExternalInstanceCreate (/approval/openapi/v3/external/approval/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#ExternalInstanceCreate) + - [三方审批实例校验](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUDNyYjL1QjM24SN0IjN) + - [ExternalInstanceCheck (/approval/openapi/v3/external/instance/check)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#ExternalInstanceCheck) + - [发送审批Bot消息](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDNyYjL4QjM24CO0IjN) + - [MessageSend (/approval/openapi/v1/message/send)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#MessageSend) + - [更新审批Bot消息](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uAjNyYjLwYjM24CM2IjN) + - [MessageUpdate (/approval/openapi/v1/message/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#MessageUpdate) - [创建审批定义](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUzNyYjL1cjM24SN3IjN) - - [Create (/approval/openapi/v2/approval/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Create) + - [ApprovalCreate (/approval/openapi/v2/approval/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#ApprovalCreate) - [审批实例抄送](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uADOzYjLwgzM24CM4MjN) - - [InstanceCc (/approval/openapi/v2/instance/cc)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#InstanceCc) + - [InstanceCc (/approval/openapi/v2/instance/cc)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#InstanceCc) - [订阅审批事件](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ucDOyUjL3gjM14yN4ITN) - - [Subscribe (/approval/openapi/v2/subscription/subscribe)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Subscribe) + - [Subscribe (/approval/openapi/v2/subscription/subscribe)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#Subscribe) - [取消订阅审批事件](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugDOyUjL4gjM14CO4ITN) - - [Unsubscribe (/approval/openapi/v2/subscription/unsubscribe)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approve?tab=doc#Unsubscribe) -- 会议室(capabilities/meeting) + - [Unsubscribe (/approval/openapi/v2/subscription/unsubscribe)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/approval?tab=doc#Unsubscribe) +- 会议室(capabilities/meeting_room) - [获取建筑物列表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ugzNyUjL4cjM14CO3ITN) - - [BuildingList (/open-apis/meeting_room/building/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#BuildingList) + - [BuildingList (/open-apis/meeting_room/building/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#BuildingList) - [查询建筑物详情](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/ukzNyUjL5cjM14SO3ITN) - - [BuildingBatchGet (/open-apis/meeting_room/building/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#BuildingBatchGet) + - [BuildingBatchGet (/open-apis/meeting_room/building/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#BuildingBatchGet) - [获取会议室列表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uADOyUjLwgjM14CM4ITN) - - [MeetingRoomList (/open-apis/meeting_room/room/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#MeetingRoomList) + - [MeetingRoomList (/open-apis/meeting_room/room/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#MeetingRoomList) - [查询会议室详情](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uEDOyUjLxgjM14SM4ITN) - - [MeetingRoomBatchGet (/open-apis/meeting_room/room/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#MeetingRoomBatchGet) + - [MeetingRoomBatchGet (/open-apis/meeting_room/room/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#MeetingRoomBatchGet) - [会议室忙闲查询](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uIDOyUjLygjM14iM4ITN) - - [MeetingRoomFreeBusyBatchGet (/open-apis/meeting_room/freebusy/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#MeetingRoomFreeBusyBatchGet) + - [MeetingRoomFreeBusyBatchGet (/open-apis/meeting_room/freebusy/batch_get)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#MeetingRoomFreeBusyBatchGet) - [回复会议室日程实例](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYzN4UjL2cDO14iN3gTN) - - [InstanceReply (/open-apis/meeting_room/instance/reply)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#InstanceReply) + - [InstanceReply (/open-apis/meeting_room/instance/reply)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#InstanceReply) - [创建建筑物](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uATNwYjLwUDM24CM1AjN) - - [BuildingCreate (/open-apis/meeting_room/building/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#BuildingCreate) + - [BuildingCreate (/open-apis/meeting_room/building/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#BuildingCreate) - [更新建筑物](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uETNwYjLxUDM24SM1AjN) - - [BuildingUpdate (/open-apis/meeting_room/building/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#BuildingUpdate) + - [BuildingUpdate (/open-apis/meeting_room/building/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#BuildingUpdate) - [删除建筑物](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMzMxYjLzMTM24yMzEjN) - - [BuildingDelete (/open-apis/meeting_room/building/delete)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#BuildingDelete) + - [BuildingDelete (/open-apis/meeting_room/building/delete)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#BuildingDelete) - [查询建筑物ID](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQzMxYjL0MTM24CNzEjN) - - [BuildingBatchGetById (/open-apis/meeting_room/building/batch_get_id)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#BuildingBatchGetById) + - [BuildingBatchGetById (/open-apis/meeting_room/building/batch_get_id)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#BuildingBatchGetById) - [创建会议室](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uITNwYjLyUDM24iM1AjN) - - [MeetingRoomCreate (/open-apis/meeting_room/room/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#MeetingRoomCreate) + - [MeetingRoomCreate (/open-apis/meeting_room/room/create)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#MeetingRoomCreate) - [更新会议室](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uMTNwYjLzUDM24yM1AjN) - - [MeetingRoomUpdate (/open-apis/meeting_room/room/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#MeetingRoomUpdate) + - [MeetingRoomUpdate (/open-apis/meeting_room/room/update)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#MeetingRoomUpdate) - [删除会议室](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUzMxYjL1MTM24SNzEjN) - - [MeetingRoomDelete (/open-apis/meeting_room/room/delete)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#MeetingRoomDelete) + - [MeetingRoomDelete (/open-apis/meeting_room/room/delete)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#MeetingRoomDelete) - [查询会议室ID](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uYzMxYjL2MTM24iNzEjN) - - [MeetingRoomBatchGetById (/open-apis/meeting_room/room/batch_get_id)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#MeetingRoomBatchGetById) + - [MeetingRoomBatchGetById (/open-apis/meeting_room/room/batch_get_id)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#MeetingRoomBatchGetById) - [获取国家地区列表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uQTNwYjL0UDM24CN1AjN) - - [CountryList (/open-apis/meeting_room/country/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#CountryList) + - [CountryList (/open-apis/meeting_room/country/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#CountryList) - [获取城市列表](https://open.feishu.cn/document/ugTM5UjL4ETO14COxkTN/uUTNwYjL1UDM24SN1AjN) - - [DistrictList (/open-apis/meeting_room/district/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting?tab=doc#DistrictList) + - [DistrictList (/open-apis/meeting_room/district/list)](https://pkg.go.dev/github.com/fastwego/feishu/apis/capabilities/meeting_room?tab=doc#DistrictList) diff --git a/feishu.go b/feishu.go index a618836..57b5c03 100644 --- a/feishu.go +++ b/feishu.go @@ -29,6 +29,8 @@ import ( // GetTenantAccessTokenFunc 获取 tenant_access_token 方法接口 type GetTenantAccessTokenFunc func() (accessToken string, err error) + +// GetAppAccessTokenFunc 获取 app_access_token 方法接口 type GetAppAccessTokenFunc func() (accessToken string, err error) /* @@ -63,7 +65,7 @@ func newApp(config AppConfig) (app *App) { instance.Client = Client{Ctx: &instance} instance.Server = Server{Ctx: &instance} - instance.Logger = log.New(os.Stdout, "[feishu] ", log.LstdFlags|log.Llongfile) + instance.Logger = log.New(os.Stdout, "[fastwego/feishu] ", log.LstdFlags|log.Llongfile) return &instance } diff --git a/go.mod b/go.mod index bb619a9..b2dba2f 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,7 @@ module github.com/fastwego/feishu go 1.14 require ( - github.com/PuerkitoBio/goquery v1.5.1 - github.com/andybalholm/cascadia v1.2.0 // indirect github.com/faabiosr/cachego v0.15.0 - github.com/gomodule/redigo v1.8.2 // indirect - github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 - golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc // indirect + github.com/gorilla/mux v1.7.4 + github.com/iancoleman/strcase v0.1.0 ) diff --git a/go.sum b/go.sum index fa523bc..ac3dbbb 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,4 @@ -github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= -github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= -github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= -github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE= -github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/faabiosr/cachego v0.15.0 h1:IqcDhvzMbL4a1c9Dek88DIWJYQ5HG//L0PKCReneOA4= github.com/faabiosr/cachego v0.15.0/go.mod h1:L2EomlU3/rUWjzFavY9Fwm8B4zZmX2X6u8kTMkETrwI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -18,14 +11,14 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= -github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8= -github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= +github.com/iancoleman/strcase v0.1.0 h1:Lar8rut26AXkJUmVOb2bRsFGv//+tJBeJLxXvpZpF1Q= +github.com/iancoleman/strcase v0.1.0/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -36,25 +29,14 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -78,6 +60,5 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal_app.go b/internal_app.go index 8c22908..7834820 100644 --- a/internal_app.go +++ b/internal_app.go @@ -42,7 +42,6 @@ var getInternalTenantAccessTokenLock sync.Mutex 如果没有 access_token 或者 已过期,那么刷新 -获得新的 access_token 后 过期时间设置为 0.9 * expiresIn 提供一定冗余 */ func (app *App) GetTenantAccessToken() (accessToken string, err error) { @@ -67,9 +66,9 @@ func (app *App) GetTenantAccessToken() (accessToken string, err error) { return } - // 提前过期 提供冗余时间 - expiresIn = int(0.9 * float64(expiresIn)) - d := time.Duration(expiresIn) * time.Second + // 提前 5min 过期 提供冗余时间 + //Token 有效期为 2 小时,在此期间调用该接口 token 不会改变。当 token 有效期小于 10 分的时候,再次请求获取 token 的时候,会生成一个新的 token,与此同时老的 token 依然有效。 + d := time.Duration(expiresIn-300) * time.Second _ = app.Cache.Save(cacheKey, accessToken, d) if app.Logger != nil { @@ -144,8 +143,6 @@ var getAppAccessTokenLock sync.Mutex 从 应用 实例 的 AppAccessToken 管理器 获取 access_token 如果没有 access_token 或者 已过期,那么刷新 - -获得新的 access_token 后 过期时间设置为 0.9 * expiresIn 提供一定冗余 */ func (app *App) GetAppAccessToken() (accessToken string, err error) { cacheKey := "app_access_token:" + app.Config.AppId @@ -168,8 +165,7 @@ func (app *App) GetAppAccessToken() (accessToken string, err error) { } // 提前过期 提供冗余时间 - expiresIn = int(0.9 * float64(expiresIn)) - d := time.Duration(expiresIn) * time.Second + d := time.Duration(expiresIn-300) * time.Second _ = app.Cache.Save(cacheKey, accessToken, d) if app.Logger != nil { diff --git a/public_app.go b/public_app.go index 20f42cc..38e7b2c 100644 --- a/public_app.go +++ b/public_app.go @@ -48,6 +48,7 @@ func NewPublicApp(config AppConfig, tenantKey string) (publicApp *PublicApp) { return } +// GetAppTicket 获取 AppTicket func (ctx *PublicApp) GetAppTicket() (appTicket string, err error) { appTicket, err = ctx.Cache.Fetch("app_ticket:" + ctx.Config.AppId) if appTicket != "" { @@ -59,6 +60,7 @@ func (ctx *PublicApp) GetAppTicket() (appTicket string, err error) { return } +// RequestAppTicket 请求重新发送 app_ticket func (ctx *PublicApp) RequestAppTicket() { params := struct { @@ -89,6 +91,7 @@ func (ctx *PublicApp) RequestAppTicket() { } +// ReceiveAppTicket 接收 app_ticket 并 存储到 缓存 func (ctx *PublicApp) ReceiveAppTicket(ticket string) (err error) { return ctx.Cache.Save("app_ticket:"+ctx.Config.AppId, ticket, 0) } @@ -124,8 +127,7 @@ func (ctx *PublicApp) GetAppAccessToken() (accessToken string, err error) { } // 提前过期 提供冗余时间 - expiresIn = int(0.9 * float64(expiresIn)) - d := time.Duration(expiresIn) * time.Second + d := time.Duration(expiresIn-300) * time.Second _ = ctx.Cache.Save(cacheKey, accessToken, d) if ctx.Logger != nil { @@ -209,7 +211,6 @@ var getPublicTenantAccessTokenLock sync.Mutex 如果没有 access_token 或者 已过期,那么刷新 -获得新的 access_token 后 过期时间设置为 0.9 * expiresIn 提供一定冗余 */ func (ctx *PublicApp) GetTenantAccessToken() (accessToken string, err error) { cacheKey := "tenant_access_token:" + ctx.TenantKey + ":" + ctx.Config.AppId @@ -234,8 +235,7 @@ func (ctx *PublicApp) GetTenantAccessToken() (accessToken string, err error) { } // 提前过期 提供冗余时间 - expiresIn = int(0.9 * float64(expiresIn)) - d := time.Duration(expiresIn) * time.Second + d := time.Duration(expiresIn-300) * time.Second _ = ctx.Cache.Save(cacheKey, accessToken, d) if ctx.Logger != nil { diff --git a/test/test.go b/test/test.go index 068f518..058d1f4 100644 --- a/test/test.go +++ b/test/test.go @@ -20,12 +20,14 @@ import ( "net/http/httptest" "sync" + "github.com/gorilla/mux" + "github.com/fastwego/feishu" ) var MockApp *feishu.App +var MockRouter *mux.Router var MockSvr *httptest.Server -var MockSvrHandler *http.ServeMux var onceSetup sync.Once // 初始化测试环境 @@ -40,16 +42,17 @@ func Setup() { }) // Mock Server - MockSvrHandler = http.NewServeMux() - MockSvr = httptest.NewServer(MockSvrHandler) + MockRouter = mux.NewRouter() + MockSvr = httptest.NewServer(MockRouter) feishu.FeishuServerUrl = MockSvr.URL // 拦截发往服务器的请求 + feishu.FeishuServerUrl2 = MockSvr.URL // Mock access token - MockSvrHandler.HandleFunc("/open-apis/auth/v3/tenant_access_token/internal/", func(w http.ResponseWriter, r *http.Request) { + MockRouter.HandleFunc("/open-apis/auth/v3/tenant_access_token/internal/", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"tenant_access_token":"ACCESS_TOKEN","expire":7200}`)) - }) - MockSvrHandler.HandleFunc("/open-apis/auth/v3/app_access_token/internal/", func(w http.ResponseWriter, r *http.Request) { + }).Methods("POST") + MockRouter.HandleFunc("/open-apis/auth/v3/app_access_token/internal/", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"app_access_token":"ACCESS_TOKEN","expire":7200}`)) - }) + }).Methods("POST") }) }