bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
142 lines
5.4 KiB
Go
142 lines
5.4 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package mail
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/larksuite/cli/shortcuts/common"
|
|
)
|
|
|
|
type messageModifyInput struct {
|
|
MessageIDs []string
|
|
AddLabelIDs []string
|
|
RemoveLabelIDs []string
|
|
AddFolder string
|
|
CustomLabelIDs []string
|
|
CustomFolderID string
|
|
ValidationAPIPlans []validationAPIPlan
|
|
}
|
|
|
|
// MailMessageModify is the `+message-modify` shortcut: apply labels, unread
|
|
// state labels, or a folder move to existing messages in batches of 20.
|
|
var MailMessageModify = common.Shortcut{
|
|
Service: "mail",
|
|
Command: "+message-modify",
|
|
Description: "Modify existing mail messages by adding/removing label IDs or moving them to a folder. Batches message IDs in groups of 20 and keeps output compact.",
|
|
Risk: "write",
|
|
Scopes: []string{"mail:user_mailbox.message:modify"},
|
|
ConditionalScopes: []string{
|
|
"mail:user_mailbox.folder:read",
|
|
},
|
|
AuthTypes: []string{"user"},
|
|
HasFormat: true,
|
|
Flags: []common.Flag{
|
|
{Name: "mailbox", Desc: "Mailbox email address that owns the messages (default: me)."},
|
|
{Name: "message-ids", Type: "string_array", Required: true, Desc: "Message IDs to modify; comma-separated or repeat the flag."},
|
|
{Name: "add-label-ids", Type: "string_slice", Desc: "Label IDs to add. System labels unread/important/other/flagged are normalized to upper case."},
|
|
{Name: "remove-label-ids", Type: "string_slice", Desc: "Label IDs to remove. System labels unread/important/other/flagged are normalized to upper case."},
|
|
{Name: "add-folder", Desc: "Folder ID to move messages to. System folders inbox/sent/spam/archive/archived are normalized; TRASH is rejected, use +message-trash."},
|
|
},
|
|
Validate: validateMessageModify,
|
|
DryRun: dryRunMessageModify,
|
|
Execute: executeMessageModify,
|
|
}
|
|
|
|
func validateMessageModify(ctx context.Context, rt *common.RuntimeContext) error {
|
|
_, err := buildMessageModifyInput(rt)
|
|
return err
|
|
}
|
|
|
|
func dryRunMessageModify(ctx context.Context, rt *common.RuntimeContext) *common.DryRunAPI {
|
|
mailboxID := resolveMailboxID(rt)
|
|
input, _ := buildMessageModifyInput(rt)
|
|
api := common.NewDryRunAPI().
|
|
Desc("Modify messages sequentially in batches of 20; dry-run does not call label/folder validation APIs").
|
|
Set("batch_size", mailMessageManageBatchSize).
|
|
Set("batches", chunkMessageManageIDs(input.MessageIDs)).
|
|
Set("validation_api_plan", input.ValidationAPIPlans)
|
|
for _, batch := range chunkMessageManageIDs(input.MessageIDs) {
|
|
api = api.POST(mailboxPath(mailboxID, "messages", "batch_modify")).
|
|
Body(messageManageBody(batch, input.AddLabelIDs, input.RemoveLabelIDs, input.AddFolder))
|
|
}
|
|
return api
|
|
}
|
|
|
|
func executeMessageModify(ctx context.Context, rt *common.RuntimeContext) error {
|
|
mailboxID := resolveMailboxID(rt)
|
|
input, err := buildMessageModifyInput(rt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := validateCustomMessageManageLabels(rt, mailboxID, input.CustomLabelIDs); err != nil {
|
|
return err
|
|
}
|
|
if err := validateCustomMessageManageFolder(rt, mailboxID, input.CustomFolderID); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(input.AddLabelIDs) == 0 && len(input.RemoveLabelIDs) == 0 && input.AddFolder == "" {
|
|
emitMessageManageSummary(rt, messageManageSummary{
|
|
SuccessMessageIDs: input.MessageIDs,
|
|
FailedMessageIDs: []messageManageFailure{},
|
|
}, true)
|
|
return nil
|
|
}
|
|
|
|
summary := messageManageSummary{FailedMessageIDs: []messageManageFailure{}}
|
|
for _, batch := range chunkMessageManageIDs(input.MessageIDs) {
|
|
_, err := rt.CallAPITyped("POST", mailboxPath(mailboxID, "messages", "batch_modify"), nil,
|
|
messageManageBody(batch, input.AddLabelIDs, input.RemoveLabelIDs, input.AddFolder))
|
|
if err != nil {
|
|
for _, id := range batch {
|
|
summary.FailedMessageIDs = append(summary.FailedMessageIDs, messageManageFailure{MessageID: id, Reason: err.Error()})
|
|
}
|
|
continue
|
|
}
|
|
summary.SuccessMessageIDs = append(summary.SuccessMessageIDs, batch...)
|
|
}
|
|
emitMessageManageSummary(rt, summary, false)
|
|
if len(summary.SuccessMessageIDs) == 0 && len(summary.FailedMessageIDs) > 0 {
|
|
return mailFailedPreconditionError("all message modify batches failed")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func buildMessageModifyInput(rt *common.RuntimeContext) (messageModifyInput, error) {
|
|
messageIDs, err := normalizeMessageManageIDs(rt.StrArray("message-ids"))
|
|
if err != nil {
|
|
return messageModifyInput{}, err
|
|
}
|
|
addLabels, customAddLabels, err := normalizeMessageManageLabels(rt.StrSlice("add-label-ids"), "--add-label-ids")
|
|
if err != nil {
|
|
return messageModifyInput{}, err
|
|
}
|
|
removeLabels, customRemoveLabels, err := normalizeMessageManageLabels(rt.StrSlice("remove-label-ids"), "--remove-label-ids")
|
|
if err != nil {
|
|
return messageModifyInput{}, err
|
|
}
|
|
if err := validateLabelIntersection(addLabels, removeLabels); err != nil {
|
|
return messageModifyInput{}, err
|
|
}
|
|
folder, customFolder, err := normalizeMessageManageFolder(rt.Str("add-folder"))
|
|
if err != nil {
|
|
return messageModifyInput{}, err
|
|
}
|
|
customLabels := append(customAddLabels, customRemoveLabels...)
|
|
customFolderID := ""
|
|
if customFolder {
|
|
customFolderID = folder
|
|
}
|
|
return messageModifyInput{
|
|
MessageIDs: messageIDs,
|
|
AddLabelIDs: addLabels,
|
|
RemoveLabelIDs: removeLabels,
|
|
AddFolder: folder,
|
|
CustomLabelIDs: customLabels,
|
|
CustomFolderID: customFolderID,
|
|
ValidationAPIPlans: messageManageValidationPlan(resolveMailboxID(rt), customLabels, customFolderID),
|
|
}, nil
|
|
}
|