feat(gmail): add single-message modify command (#281) (thanks @zerone0x)
This commit is contained in:
parent
643a255679
commit
d448264a27
@ -11,6 +11,7 @@
|
||||
- Sheets: add `sheets create --parent` to place new spreadsheets in a Drive folder. (#424) — thanks @ManManavadaria.
|
||||
- Calendar: add `calendar subscribe` (aliases `sub`, `add-calendar`) to add a shared calendar to the current account’s calendar list. (#327) — thanks @cdthompson.
|
||||
- Gmail: add `watch serve --history-types` filtering (`messageAdded|messageDeleted|labelAdded|labelRemoved`) and include `deletedMessageIds` in webhook payloads. (#168) — thanks @salmonumbrella.
|
||||
- Gmail: add `gmail messages modify` for single-message label changes, complementing thread- and batch-level modify flows. (#281) — thanks @zerone0x.
|
||||
- Contacts: support `--org`, `--title`, `--url`, `--note`, and `--custom` on create/update; include custom fields in get output with deterministic ordering. (#199) — thanks @phuctm97.
|
||||
- Drive: add `drive ls --all` (alias `--global`) to list across all accessible files; make `--all` and `--parent` mutually exclusive. (#107) — thanks @struong.
|
||||
- Docs: update install docs to use the official Homebrew core formula (`brew install gogcli`). (#361) — thanks @zeldrisho.
|
||||
|
||||
@ -109,14 +109,11 @@ func (c *GmailBatchModifyCmd) Run(ctx context.Context, flags *RootFlags) error {
|
||||
return err
|
||||
}
|
||||
|
||||
idMap, err := fetchLabelNameToID(svc)
|
||||
addIDs, removeIDs, err := resolveModifyLabelIDs(svc, addLabels, removeLabels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addIDs := resolveLabelIDs(addLabels, idMap)
|
||||
removeIDs := resolveLabelIDs(removeLabels, idMap)
|
||||
|
||||
err = svc.Users.Messages.BatchModify("me", &gmail.BatchModifyMessagesRequest{
|
||||
Ids: ids,
|
||||
AddLabelIds: addIDs,
|
||||
|
||||
@ -30,6 +30,15 @@ func resolveLabelIDs(labels []string, nameToID map[string]string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
func resolveModifyLabelIDs(svc *gmail.Service, addLabels, removeLabels []string) ([]string, []string, error) {
|
||||
idMap, err := fetchLabelNameToID(svc)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return resolveLabelIDs(addLabels, idMap), resolveLabelIDs(removeLabels, idMap), nil
|
||||
}
|
||||
|
||||
func ensureLabelNameAvailable(svc *gmail.Service, name string) error {
|
||||
idMap, err := fetchLabelNameToID(svc)
|
||||
if err != nil {
|
||||
|
||||
@ -186,14 +186,11 @@ func (c *GmailMessagesModifyCmd) Run(ctx context.Context, flags *RootFlags) erro
|
||||
return err
|
||||
}
|
||||
|
||||
idMap, err := fetchLabelNameToID(svc)
|
||||
addIDs, removeIDs, err := resolveModifyLabelIDs(svc, addLabels, removeLabels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addIDs := resolveLabelIDs(addLabels, idMap)
|
||||
removeIDs := resolveLabelIDs(removeLabels, idMap)
|
||||
|
||||
_, err = svc.Users.Messages.Modify("me", messageID, &gmail.ModifyMessageRequest{
|
||||
AddLabelIds: addIDs,
|
||||
RemoveLabelIds: removeIDs,
|
||||
|
||||
@ -39,7 +39,7 @@ func TestGmailMessagesModifyCmd_JSON(t *testing.T) {
|
||||
RemoveLabelIds []string `json:"removeLabelIds"`
|
||||
}
|
||||
_ = json.NewDecoder(r.Body).Decode(&body)
|
||||
if len(body.AddLabelIds) != 1 || body.AddLabelIds[0] != "TRASH" {
|
||||
if len(body.AddLabelIds) != 1 || body.AddLabelIds[0] != "Label_1" {
|
||||
http.Error(w, "bad addLabelIds", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@ -79,7 +79,7 @@ func TestGmailMessagesModifyCmd_JSON(t *testing.T) {
|
||||
|
||||
if err := runKong(t, &GmailMessagesModifyCmd{}, []string{
|
||||
"msg1",
|
||||
"--add", "TRASH",
|
||||
"--add", "Custom",
|
||||
"--remove", "INBOX",
|
||||
}, ctx, flags); err != nil {
|
||||
t.Fatalf("execute: %v", err)
|
||||
@ -97,7 +97,7 @@ func TestGmailMessagesModifyCmd_JSON(t *testing.T) {
|
||||
if parsed.Modified != "msg1" {
|
||||
t.Fatalf("unexpected modified: %q", parsed.Modified)
|
||||
}
|
||||
if len(parsed.AddedLabels) != 1 || parsed.AddedLabels[0] != "TRASH" {
|
||||
if len(parsed.AddedLabels) != 1 || parsed.AddedLabels[0] != "Label_1" {
|
||||
t.Fatalf("unexpected added labels: %#v", parsed.AddedLabels)
|
||||
}
|
||||
if len(parsed.RemovedLabels) != 1 || parsed.RemovedLabels[0] != "INBOX" {
|
||||
@ -113,7 +113,7 @@ func TestGmailMessagesModifyCmd_JSON(t *testing.T) {
|
||||
|
||||
if err := runKong(t, &GmailMessagesModifyCmd{}, []string{
|
||||
"msg1",
|
||||
"--add", "TRASH",
|
||||
"--add", "Custom",
|
||||
"--remove", "INBOX",
|
||||
}, ctx, flags); err != nil {
|
||||
t.Fatalf("execute plain: %v", err)
|
||||
@ -148,4 +148,11 @@ func TestGmailMessagesModifyCmd_ValidationErrors(t *testing.T) {
|
||||
t.Fatalf("expected validation error, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("empty message id", func(t *testing.T) {
|
||||
err := runKong(t, &GmailMessagesModifyCmd{}, []string{"", "--add", "INBOX"}, ctx, flags)
|
||||
if err == nil || !strings.Contains(err.Error(), "empty messageId") {
|
||||
t.Fatalf("expected empty messageId error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -212,15 +212,11 @@ func (c *GmailThreadModifyCmd) Run(ctx context.Context, flags *RootFlags) error
|
||||
return err
|
||||
}
|
||||
|
||||
// Resolve label names to IDs
|
||||
idMap, err := fetchLabelNameToID(svc)
|
||||
addIDs, removeIDs, err := resolveModifyLabelIDs(svc, addLabels, removeLabels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addIDs := resolveLabelIDs(addLabels, idMap)
|
||||
removeIDs := resolveLabelIDs(removeLabels, idMap)
|
||||
|
||||
// Use Gmail's Threads.Modify API
|
||||
_, err = svc.Users.Threads.Modify("me", threadID, &gmail.ModifyThreadRequest{
|
||||
AddLabelIds: addIDs,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user