Skip to content

Commit 4878129

Browse files
Ortesclaude
andcommitted
fix(send-poll): preserve whatsmeow's 0=unlimited semantics
Reverts the over-restrictive validation introduced in 9b8e7f0: whatsmeow's BuildPollCreation treats selectableOptionCount=0 as "multi-select with no limit" (msgsecret.go:300-308) and silently coerces out-of-range values to 0. Forcing a minimum of 1 and defaulting omitted requests to 1 silently removed access to the unlimited-select mode and rewrote caller intent. - Allow 0 (unlimited) again in both Python and Go validation; reject only negative or > len(options). - Drop the *int pointer indirection on SendPollRequest — int's zero-value already maps cleanly to whatsmeow's "unlimited" sentinel. - Document the three-way semantics on the request type and update error messages. - Replace the zero-rejection test with one asserting 0 is accepted and forwarded as-is, plus a negative-value rejection test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 305f964 commit 4878129

2 files changed

Lines changed: 28 additions & 16 deletions

File tree

whatsapp-bridge/main.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -819,14 +819,17 @@ func sendWhatsAppMessage(client *whatsmeow.Client, recipient string, message str
819819
return true, fmt.Sprintf("Message sent to %s", recipient)
820820
}
821821

822-
// SendPollRequest represents the request body for the send poll API
822+
// SendPollRequest represents the request body for the send poll API.
823+
// SelectableOptionCount follows whatsmeow semantics:
824+
//
825+
// 0 = multi-select with no limit (also the zero-value default when omitted)
826+
// 1 = single-select
827+
// N = multi-select up to N (1 < N <= len(Options))
823828
type SendPollRequest struct {
824-
Recipient string `json:"recipient"`
825-
Name string `json:"name"`
826-
Options []string `json:"options"`
827-
// Pointer so we can distinguish "omitted" (nil → default to 1)
828-
// from "explicitly set to 0" (rejected by validation).
829-
SelectableOptionCount *int `json:"selectable_option_count,omitempty"`
829+
Recipient string `json:"recipient"`
830+
Name string `json:"name"`
831+
Options []string `json:"options"`
832+
SelectableOptionCount int `json:"selectable_option_count,omitempty"`
830833
}
831834

832835
// resolveRecipientJID parses a phone number or JID string and resolves PN -> LID
@@ -1518,16 +1521,14 @@ func startRESTServer(client *whatsmeow.Client, messageStore *MessageStore, port
15181521
return
15191522
}
15201523
}
1521-
selectable := 1
1522-
if req.SelectableOptionCount != nil {
1523-
selectable = *req.SelectableOptionCount
1524-
}
1525-
if selectable < 1 || selectable > len(req.Options) {
1526-
http.Error(w, "selectable_option_count must be between 1 and len(options)", http.StatusBadRequest)
1524+
// whatsmeow coerces out-of-range values to 0, which silently changes the
1525+
// poll's selection mode. Reject them upfront so the caller knows.
1526+
if req.SelectableOptionCount < 0 || req.SelectableOptionCount > len(req.Options) {
1527+
http.Error(w, "selectable_option_count must be 0 (unlimited) or between 1 and len(options)", http.StatusBadRequest)
15271528
return
15281529
}
15291530

1530-
success, message := sendWhatsAppPoll(client, req.Recipient, req.Name, req.Options, selectable)
1531+
success, message := sendWhatsAppPoll(client, req.Recipient, req.Name, req.Options, req.SelectableOptionCount)
15311532

15321533
w.Header().Set("Content-Type", "application/json")
15331534
if !success {

whatsapp-mcp-server/tests/test_send_poll.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,22 @@ def test_selectable_count_out_of_range(self):
3636
assert not ok
3737
assert "selectable_option_count" in msg
3838

39-
def test_selectable_count_zero_rejected(self):
40-
ok, msg = send_poll("123@s.whatsapp.net", "Q?", ["a", "b"], selectable_option_count=0)
39+
def test_selectable_count_negative_rejected(self):
40+
ok, msg = send_poll("123@s.whatsapp.net", "Q?", ["a", "b"], selectable_option_count=-1)
4141
assert not ok
4242
assert "selectable_option_count" in msg
4343

44+
def test_selectable_count_zero_allowed_unlimited(self):
45+
# whatsmeow treats 0 as "multi-select with no limit" — must remain valid.
46+
with patch("whatsapp.requests.post") as mock_post:
47+
mock_post.return_value.status_code = 200
48+
mock_post.return_value.json.return_value = {"success": True, "message": "Poll sent to 123"}
49+
50+
ok, _ = send_poll("123@s.whatsapp.net", "Q?", ["a", "b"], selectable_option_count=0)
51+
52+
assert ok
53+
assert mock_post.call_args.kwargs["json"]["selectable_option_count"] == 0
54+
4455
def test_valid_request_calls_bridge(self):
4556
with patch("whatsapp.requests.post") as mock_post:
4657
mock_post.return_value.status_code = 200

0 commit comments

Comments
 (0)