Add /chat/pin endpoint to pin and unpin messages#336
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new /chat/pin endpoint to pin or unpin messages in individual or group chats, complete with documentation in API.md, route registration, handler implementation in handlers.go, and integration tests in pin_test.go. The reviewer recommended supporting the me: prefix convention on message IDs to allow users to pin or unpin their own messages, utilizing the idiomatic !senderJID.IsEmpty() check, and updating the response payload, logging, and documentation to reflect this prefix change.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| key := &waCommon.MessageKey{ | ||
| RemoteJID: proto.String(chatJID.String()), | ||
| FromMe: proto.Bool(false), | ||
| ID: proto.String(t.Id), | ||
| } | ||
| if senderJID.String() != "" { | ||
| key.Participant = proto.String(senderJID.String()) | ||
| } |
There was a problem hiding this comment.
To allow users to pin or unpin their own messages, we should support the me: prefix convention on the message ID (similar to how it is handled in the React endpoint). Additionally, we should use the idiomatic !senderJID.IsEmpty() check instead of senderJID.String() != "".
fromMe := false
msgID := t.Id
if strings.HasPrefix(msgID, "me:") {
fromMe = true
msgID = msgID[len("me:"):]
}
key := &waCommon.MessageKey{
RemoteJID: proto.String(chatJID.String()),
FromMe: proto.Bool(fromMe),
ID: proto.String(msgID),
}
if !senderJID.IsEmpty() {
key.Participant = proto.String(senderJID.String())
}| response := map[string]interface{}{ | ||
| "Chat": chatJID.String(), | ||
| "Id": t.Id, | ||
| "Timestamp": resp.Timestamp.UTC().Format(time.RFC3339), | ||
| } | ||
| if pin { | ||
| response["Details"] = "Message pinned" | ||
| response["DurationSeconds"] = duration | ||
| log.Info().Str("id", t.Id).Str("chat", chatJID.String()).Uint32("duration", duration).Msg("Message pinned") | ||
| } else { | ||
| response["Details"] = "Message unpinned" | ||
| log.Info().Str("id", t.Id).Str("chat", chatJID.String()).Msg("Message unpinned") | ||
| } |
There was a problem hiding this comment.
Update the response payload and log messages to use the stripped msgID instead of t.Id to ensure consistency with other endpoints (like React).
| response := map[string]interface{}{ | |
| "Chat": chatJID.String(), | |
| "Id": t.Id, | |
| "Timestamp": resp.Timestamp.UTC().Format(time.RFC3339), | |
| } | |
| if pin { | |
| response["Details"] = "Message pinned" | |
| response["DurationSeconds"] = duration | |
| log.Info().Str("id", t.Id).Str("chat", chatJID.String()).Uint32("duration", duration).Msg("Message pinned") | |
| } else { | |
| response["Details"] = "Message unpinned" | |
| log.Info().Str("id", t.Id).Str("chat", chatJID.String()).Msg("Message unpinned") | |
| } | |
| response := map[string]interface{}{ | |
| "Chat": chatJID.String(), | |
| "Id": msgID, | |
| "Timestamp": resp.Timestamp.UTC().Format(time.RFC3339), | |
| } | |
| if pin { | |
| response["Details"] = "Message pinned" | |
| response["DurationSeconds"] = duration | |
| log.Info().Str("id", msgID).Str("chat", chatJID.String()).Uint32("duration", duration).Msg("Message pinned") | |
| } else { | |
| response["Details"] = "Message unpinned" | |
| log.Info().Str("id", msgID).Str("chat", chatJID.String()).Msg("Message unpinned") | |
| } |
| |---|---|---|---| | ||
| | `Chat` | Yes | string | Target chat JID. For groups, the group JID ending in `@g.us`. | | ||
| | `Sender` | Required for groups | string | JID of the original message sender. Required for group messages because the message key includes the participant. Optional for one-to-one chats. | | ||
| | `Id` | Yes | string | WhatsApp message ID of the message to pin or unpin. | |
There was a problem hiding this comment.
To document the ability to pin/unpin your own messages using the me: prefix, we should update the description of the Id field.
| | `Id` | Yes | string | WhatsApp message ID of the message to pin or unpin. | | |
| | `Id` | Yes | string | WhatsApp message ID of the message to pin or unpin. Prefix with `me:` to pin/unpin your own messages (e.g., `me:3EB0ABCDEF1234567890`). | |
Adds an authenticated
POST /chat/pinendpoint that pins and unpins an existing message in individual chats and groups, mapping to whatsmeow'sPinInChatMessage.This PR also bumps
go.mau.fi/whatsmeowto latest as it is required for correctPinInChatMessagesend behavior (older versions send the stanza without the edit attribute and fail silently).