227 lines
6.1 KiB
Go
227 lines
6.1 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// 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 helpers
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cobracmd"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/i18n"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/executor"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
const todoListPageSizeMax = 20
|
|
|
|
func init() {
|
|
RegisterPublic(func() Handler {
|
|
return todoHandler{}
|
|
})
|
|
}
|
|
|
|
type todoHandler struct{}
|
|
|
|
func (todoHandler) Name() string {
|
|
return "todo"
|
|
}
|
|
|
|
func (todoHandler) Command(runner executor.Runner) *cobra.Command {
|
|
root := &cobra.Command{
|
|
Use: "todo",
|
|
Short: "Todo helper overrides",
|
|
Args: cobra.NoArgs,
|
|
TraverseChildren: true,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return cmd.Help()
|
|
},
|
|
}
|
|
|
|
task := &cobra.Command{
|
|
Use: "task",
|
|
Short: i18n.T("创建 / 查询 / 更新 / 删除待办"),
|
|
Args: cobra.NoArgs,
|
|
TraverseChildren: true,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return cmd.Help()
|
|
},
|
|
}
|
|
task.AddCommand(newTodoTaskListCommand(runner))
|
|
root.AddCommand(task)
|
|
return root
|
|
}
|
|
|
|
func newTodoTaskListCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "list",
|
|
Short: i18n.T("查询待办列表"),
|
|
Example: ` dws todo task list --page 1 --size 20 --status false`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
page, _ := cmd.Flags().GetString("page")
|
|
sizeRaw, _ := cmd.Flags().GetString("size")
|
|
status, _ := cmd.Flags().GetString("status")
|
|
|
|
page = normalizePage(page)
|
|
size := normalizeSize(sizeRaw)
|
|
summaryParams := todoListRequestParams(page, strconv.Itoa(size), status)
|
|
invocation := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd),
|
|
"todo",
|
|
"get_user_todos_in_current_org",
|
|
summaryParams,
|
|
)
|
|
|
|
if size <= todoListPageSizeMax {
|
|
result, err := runner.Run(cmd.Context(), invocation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
}
|
|
|
|
if commandDryRun(cmd) {
|
|
invocation.DryRun = true
|
|
return writeCommandPayload(cmd, todoListPreviewResult(invocation, size, "automatic pagination preview"))
|
|
}
|
|
|
|
startPage, _ := strconv.Atoi(page)
|
|
if startPage < 1 {
|
|
startPage = 1
|
|
}
|
|
merged := make([]any, 0, size)
|
|
for pageNum := startPage; len(merged) < size; pageNum++ {
|
|
pageParams := todoListRequestParams(strconv.Itoa(pageNum), strconv.Itoa(todoListPageSizeMax), status)
|
|
pageInvocation := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd),
|
|
"todo",
|
|
"get_user_todos_in_current_org",
|
|
pageParams,
|
|
)
|
|
pageResult, err := runner.Run(cmd.Context(), pageInvocation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !pageResult.Invocation.Implemented && len(helperResponseContent(pageResult)) == 0 {
|
|
invocation.DryRun = pageResult.Invocation.DryRun
|
|
return writeCommandPayload(cmd, todoListPreviewResult(invocation, size, "automatic pagination requires runtime execution"))
|
|
}
|
|
|
|
cards := todoCardsFromResult(pageResult)
|
|
if len(cards) == 0 {
|
|
break
|
|
}
|
|
for _, card := range cards {
|
|
merged = append(merged, card)
|
|
if len(merged) >= size {
|
|
break
|
|
}
|
|
}
|
|
if len(cards) < todoListPageSizeMax {
|
|
break
|
|
}
|
|
}
|
|
|
|
invocation.Implemented = true
|
|
return writeCommandPayload(cmd, executor.Result{
|
|
Invocation: invocation,
|
|
Response: map[string]any{
|
|
"content": map[string]any{
|
|
"result": map[string]any{
|
|
"todoCards": merged,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
|
|
cmd.Flags().String("page", "1", i18n.T("页码 (必填)"))
|
|
cmd.Flags().String("size", "20", i18n.T("获取数量,超过 20 自动分页 (默认 20)"))
|
|
cmd.Flags().String("status", "", i18n.T("true=已完成, false=未完成"))
|
|
return cmd
|
|
}
|
|
|
|
func normalizePage(raw string) string {
|
|
if trimmed := strings.TrimSpace(raw); trimmed != "" {
|
|
return trimmed
|
|
}
|
|
return "1"
|
|
}
|
|
|
|
func normalizeSize(raw string) int {
|
|
value, err := strconv.Atoi(strings.TrimSpace(raw))
|
|
if err != nil || value < 1 {
|
|
return todoListPageSizeMax
|
|
}
|
|
return value
|
|
}
|
|
|
|
func estimateTodoListRequests(size int) int {
|
|
return (size + todoListPageSizeMax - 1) / todoListPageSizeMax
|
|
}
|
|
|
|
func todoListPreviewResult(invocation executor.Invocation, size int, note string) executor.Result {
|
|
response := map[string]any{
|
|
"estimated_requests": estimateTodoListRequests(size),
|
|
"page_size_limit": todoListPageSizeMax,
|
|
"note": note,
|
|
}
|
|
if invocation.DryRun {
|
|
response["dry_run"] = true
|
|
}
|
|
return executor.Result{
|
|
Invocation: invocation,
|
|
Response: response,
|
|
}
|
|
}
|
|
|
|
func todoListRequestParams(page, pageSize, status string) map[string]any {
|
|
pageSize = strings.TrimSpace(pageSize)
|
|
if pageSize == "" {
|
|
pageSize = strconv.Itoa(todoListPageSizeMax)
|
|
}
|
|
params := map[string]any{
|
|
"pageNum": normalizePage(page),
|
|
"pageSize": pageSize,
|
|
}
|
|
status = strings.TrimSpace(status)
|
|
if status != "" {
|
|
params["isDone"] = status
|
|
params["todoStatus"] = status
|
|
}
|
|
return params
|
|
}
|
|
|
|
func todoCardsFromResult(result executor.Result) []any {
|
|
content := helperResponseContent(result)
|
|
if len(content) == 0 {
|
|
return nil
|
|
}
|
|
if payload, ok := content["result"].(map[string]any); ok {
|
|
if cards, ok := payload["todoCards"].([]any); ok {
|
|
return cards
|
|
}
|
|
}
|
|
if cards, ok := content["todoCards"].([]any); ok {
|
|
return cards
|
|
}
|
|
return nil
|
|
}
|