feishu sheets: fix table data write via values_batch_update with response validation

This commit is contained in:
DBT
2026-02-27 07:46:09 +00:00
parent 791f9ae63e
commit 752884fb72

View File

@@ -10,6 +10,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -465,43 +466,89 @@ func firstString(m map[string]interface{}, paths ...string) string {
var cur interface{} = m var cur interface{} = m
ok := true ok := true
for _, seg := range parts { for _, seg := range parts {
n, yes := cur.(map[string]interface{}) if obj, yes := cur.(map[string]interface{}); yes {
if !yes { ok=false; break } cur = obj[seg]
cur = n[seg] continue
}
if arr, yes := cur.([]interface{}); yes {
idx, err := strconv.Atoi(seg)
if err != nil || idx < 0 || idx >= len(arr) {
ok = false
break
}
cur = arr[idx]
continue
}
ok = false
break
}
if !ok {
continue
}
if s, yes := cur.(string); yes && strings.TrimSpace(s) != "" {
return s
} }
if !ok { continue }
if s, yes := cur.(string); yes && strings.TrimSpace(s) != "" { return s }
} }
return "" return ""
} }
func (c *FeishuChannel) createFeishuSheetFromTable(ctx context.Context, name string, rows [][]string) (string, error) { func (c *FeishuChannel) createFeishuSheetFromTable(ctx context.Context, name string, rows [][]string) (string, error) {
tok, err := c.getTenantAccessToken(ctx) tok, err := c.getTenantAccessToken(ctx)
if err != nil { return "", err } if err != nil {
createBody, _ := json.Marshal(map[string]interface{}{ "title": name }) return "", err
}
createBody, _ := json.Marshal(map[string]interface{}{"title": name})
req, _ := http.NewRequestWithContext(ctx, http.MethodPost, "https://open.feishu.cn/open-apis/sheets/v3/spreadsheets", bytes.NewReader(createBody)) req, _ := http.NewRequestWithContext(ctx, http.MethodPost, "https://open.feishu.cn/open-apis/sheets/v3/spreadsheets", bytes.NewReader(createBody))
req.Header.Set("Authorization", "Bearer "+tok) req.Header.Set("Authorization", "Bearer "+tok)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req) resp, err := http.DefaultClient.Do(req)
if err != nil { return "", err } if err != nil {
return "", err
}
defer resp.Body.Close() defer resp.Body.Close()
rb, _ := io.ReadAll(resp.Body) rb, _ := io.ReadAll(resp.Body)
var obj map[string]interface{} var obj map[string]interface{}
if err := json.Unmarshal(rb, &obj); err != nil { return "", err } if err := json.Unmarshal(rb, &obj); err != nil {
if code, _ := obj["code"].(float64); code != 0 { return "", fmt.Errorf("create sheet code=%v msg=%v", obj["code"], obj["msg"]) } return "", err
}
if code, _ := obj["code"].(float64); code != 0 {
return "", fmt.Errorf("create sheet code=%v msg=%v", obj["code"], obj["msg"])
}
spToken := firstString(obj, "data.spreadsheet.spreadsheet_token", "data.spreadsheet_token", "data.spreadsheetToken") spToken := firstString(obj, "data.spreadsheet.spreadsheet_token", "data.spreadsheet_token", "data.spreadsheetToken")
sheetID := firstString(obj, "data.spreadsheet.sheet_id", "data.sheet_id", "data.sheetId") sheetID := firstString(obj, "data.spreadsheet.sheet_id", "data.sheet_id", "data.sheetId", "data.sheet_ids.0")
if spToken == "" { return "", fmt.Errorf("no spreadsheet token in response") } if spToken == "" {
if sheetID == "" { sheetID = "Sheet1" } return "", fmt.Errorf("no spreadsheet token in response")
}
if sheetID == "" {
sheetID = firstString(obj, "data.sheets.0.sheet_id")
}
if sheetID == "" {
sheetID = "Sheet1"
}
if len(rows) > 0 { if len(rows) > 0 {
vr := map[string]interface{}{ "valueRange": map[string]interface{}{ "range": fmt.Sprintf("%s!A1", sheetID), "values": rows } } payload := map[string]interface{}{
vb, _ := json.Marshal(vr) "valueRanges": []map[string]interface{}{{
vreq, _ := http.NewRequestWithContext(ctx, http.MethodPut, fmt.Sprintf("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values", spToken), bytes.NewReader(vb)) "range": fmt.Sprintf("%s!A1", sheetID),
"values": rows,
}},
}
vb, _ := json.Marshal(payload)
vreq, _ := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values_batch_update", spToken), bytes.NewReader(vb))
vreq.Header.Set("Authorization", "Bearer "+tok) vreq.Header.Set("Authorization", "Bearer "+tok)
vreq.Header.Set("Content-Type", "application/json") vreq.Header.Set("Content-Type", "application/json")
vresp, err := http.DefaultClient.Do(vreq) vresp, err := http.DefaultClient.Do(vreq)
if err == nil { if err != nil {
defer vresp.Body.Close() return "", fmt.Errorf("write sheet values failed: %w", err)
}
defer vresp.Body.Close()
vrb, _ := io.ReadAll(vresp.Body)
var vobj map[string]interface{}
if err := json.Unmarshal(vrb, &vobj); err != nil {
return "", fmt.Errorf("write sheet values decode failed: %w", err)
}
if code, _ := vobj["code"].(float64); code != 0 {
return "", fmt.Errorf("write sheet values code=%v msg=%v", vobj["code"], vobj["msg"])
} }
} }
return "https://feishu.cn/sheets/" + spToken, nil return "https://feishu.cn/sheets/" + spToken, nil