groupme-lib/messages_api.go

158 lines
4.5 KiB
Go

// Package groupme defines a client capable of executing API commands for the GroupMe chat service
package groupme
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
"github.com/google/uuid"
)
// GroupMe documentation: https://dev.groupme.com/docs/v3#messages
/*//////// Endpoints ////////*/
const (
// Used to build other endpoints
messagesEndpointRoot = groupEndpointRoot + "/messages"
indexMessagesEndpoint = messagesEndpointRoot // GET
createMessagesEndpoint = messagesEndpointRoot // POST
)
// IndexMessagesQuery defines the optional URL parameters for IndexMessages
type IndexMessagesQuery struct {
// Returns messages created before the given message ID
BeforeID ID
// Returns most recent messages created after the given message ID
SinceID ID
// Returns messages created immediately after the given message ID
AfterID ID
// Number of messages returned. Default is 20. Max is 100.
Limit int
}
func (q IndexMessagesQuery) String() string {
return marshal(&q)
}
// IndexMessagesResponse contains the count and set of
// messages returned by the IndexMessages API request
type IndexMessagesResponse struct {
Count int `json:"count"`
Messages []*Message `json:"messages"`
}
func (r IndexMessagesResponse) String() string {
return marshal(&r)
}
/*
IndexMessages - Retrieves messages for a group.
By default, messages are returned in groups of 20, ordered by
created_at descending. This can be raised or lowered by passing
a limit parameter, up to a maximum of 100 messages.
Messages can be scanned by providing a message ID as either the
before_id, since_id, or after_id parameter. If before_id is
provided, then messages immediately preceding the given message
will be returned, in descending order. This can be used to
continually page back through a group's messages.
The after_id parameter will return messages that immediately
follow a given message, this time in ascending order (which
makes it easy to pick off the last result for continued
pagination).
Finally, the since_id parameter also returns messages created
after the given message, but it retrieves the most recent
messages. For example, if more than twenty messages are created
after the since_id message, using this parameter will omit the
messages that immediately follow the given message. This is a
bit counterintuitive, so take care.
If no messages are found (e.g. when filtering with before_id)
we return code 304.
Note that for historical reasons, likes are returned as an
array of user ids in the favorited_by key.
*/
func (c *Client) IndexMessages(ctx context.Context, groupID ID, req *IndexMessagesQuery, authToken string) (IndexMessagesResponse, error) {
url := fmt.Sprintf(c.endpointBase+indexMessagesEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil)
if err != nil {
return IndexMessagesResponse{}, err
}
URL := httpReq.URL
query := URL.Query()
if req != nil {
if req.BeforeID != "" {
query.Add("before_id", req.BeforeID.String())
}
if req.SinceID != "" {
query.Add("since_id", req.SinceID.String())
}
if req.AfterID != "" {
query.Add("after_id", req.AfterID.String())
}
if req.Limit != 0 {
query.Add("limit", strconv.Itoa(req.Limit))
}
}
URL.RawQuery = query.Encode()
var resp IndexMessagesResponse
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return IndexMessagesResponse{}, err
}
return resp, nil
}
/*
CreateMessage - Send a message to a group
If you want to attach an image, you must first process it
through our image service.
Attachments of type emoji rely on data from emoji PowerUps.
Clients use a placeholder character in the message text and
specify a replacement charmap to substitute emoji characters
The character map is an array of arrays containing rune data
([[{pack_id,offset}],...]).
The placeholder should be a high-point/invisible UTF-8 character.
*/
func (c *Client) CreateMessage(ctx context.Context, groupID ID, m *Message, authToken string) (*Message, error) {
URL := fmt.Sprintf(c.endpointBase+createMessagesEndpoint, groupID)
m.SourceGUID = uuid.New().String()
var data = struct {
Message *Message `json:"message"`
}{
m,
}
jsonBytes, err := json.Marshal(&data)
if err != nil {
return nil, err
}
httpReq, err := http.NewRequest("POST", URL, bytes.NewBuffer(jsonBytes))
if err != nil {
return nil, err
}
var resp struct {
*Message `json:"message"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
return resp.Message, nil
}