Compare commits

...

26 Commits

Author SHA1 Message Date
f9c1b24194 Bump fayec 2023-09-26 13:03:49 -05:00
a58e4100e1 Upgrading fayec 2023-09-25 15:29:44 -05:00
7b9e2a8d29 Fixing bug where nil handler was called 2023-09-24 15:36:17 -04:00
d81730e3e7 Handlers are now fired for individual users 2023-09-22 16:10:44 -05:00
08bfe83ba4 Updating API to re-use client for multiple users 2023-09-20 16:47:47 -05:00
c0f3da8060 Using updated fayec client 2023-09-19 16:28:22 -05:00
5727a20506 Updating package name 2023-09-18 21:37:41 -05:00
3e9851b2c0 Usinc fayec client instead of wray 2023-09-18 21:35:00 -05:00
Sumner Evans
8f23e04eea
namespace under beeper
Signed-off-by: Sumner Evans <sumner@beeper.com>
2022-10-21 15:59:45 -05:00
Karmanyaah Malhotra
c2dbe7021e fix 2021-05-08 16:01:24 -04:00
Karmanyaah Malhotra
6eba33b3be relations api 2021-05-08 15:54:12 -04:00
Karmanyaah Malhotra
7961d30a51 Dependencies 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
12931fb275 ChatID name different over push 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
65299d9606 Update example to use new real-time api 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
aa216ed4af Reformat real_time 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
28b2d85660 logging 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
8dd5993481 Fix panic 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
042fb9a951 fix golangcilint issues 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
b6715c2375 added more conditions 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
c5d6c8a29c replace not required in production version 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
d6a8b0818f Add many types of handling
fix listen loop
improve example
2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
da7bc977a3 Add membership 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
eeb2f88b97 Use interfaces and callbacks 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
784cfe93c1 real time push basics 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
6d42a230d1 Fix bugs with direct message api 2021-05-08 15:44:18 -04:00
Karmanyaah Malhotra
7166300503 Add more attachment values 2021-05-08 15:44:18 -04:00
20 changed files with 827 additions and 113 deletions

View File

@ -23,7 +23,7 @@ const (
/*//////// API Requests ////////*/ /*//////// API Requests ////////*/
// IndexBlock - A list of contacts you have blocked. These people cannot DM you // IndexBlock - A list of contacts you have blocked. These people cannot DM you
func (c *Client) IndexBlock(ctx context.Context, userID string) ([]*Block, error) { func (c *Client) IndexBlock(ctx context.Context, userID string, authToken string) ([]*Block, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexBlocksEndpoint, nil) httpReq, err := http.NewRequest("GET", c.endpointBase+indexBlocksEndpoint, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -37,7 +37,7 @@ func (c *Client) IndexBlock(ctx context.Context, userID string) ([]*Block, error
var resp struct { var resp struct {
Blocks []*Block `json:"blocks"` Blocks []*Block `json:"blocks"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -46,7 +46,7 @@ func (c *Client) IndexBlock(ctx context.Context, userID string) ([]*Block, error
} }
// BlockBetween - Asks if a block exists between you and another user id // BlockBetween - Asks if a block exists between you and another user id
func (c *Client) BlockBetween(ctx context.Context, userID, otherUserID string) (bool, error) { func (c *Client) BlockBetween(ctx context.Context, userID, otherUserID string, authToken string) (bool, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+blockBetweenEndpoint, nil) httpReq, err := http.NewRequest("GET", c.endpointBase+blockBetweenEndpoint, nil)
if err != nil { if err != nil {
return false, err return false, err
@ -61,7 +61,7 @@ func (c *Client) BlockBetween(ctx context.Context, userID, otherUserID string) (
var resp struct { var resp struct {
Between bool `json:"between"` Between bool `json:"between"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -70,7 +70,7 @@ func (c *Client) BlockBetween(ctx context.Context, userID, otherUserID string) (
} }
// CreateBlock - Creates a block between you and the contact // CreateBlock - Creates a block between you and the contact
func (c *Client) CreateBlock(ctx context.Context, userID, otherUserID string) (*Block, error) { func (c *Client) CreateBlock(ctx context.Context, userID, otherUserID string, authToken string) (*Block, error) {
httpReq, err := http.NewRequest("POST", c.endpointBase+createBlockEndpoint, nil) httpReq, err := http.NewRequest("POST", c.endpointBase+createBlockEndpoint, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -85,7 +85,7 @@ func (c *Client) CreateBlock(ctx context.Context, userID, otherUserID string) (*
var resp struct { var resp struct {
Block *Block `json:"block"` Block *Block `json:"block"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -94,7 +94,7 @@ func (c *Client) CreateBlock(ctx context.Context, userID, otherUserID string) (*
} }
// Unblock - Removes block between you and other user // Unblock - Removes block between you and other user
func (c *Client) Unblock(ctx context.Context, userID, otherUserID string) error { func (c *Client) Unblock(ctx context.Context, userID, otherUserID string, authToken string) error {
httpReq, err := http.NewRequest("DELETE", c.endpointBase+unblockEndpoint, nil) httpReq, err := http.NewRequest("DELETE", c.endpointBase+unblockEndpoint, nil)
if err != nil { if err != nil {
return err return err
@ -106,7 +106,7 @@ func (c *Client) Unblock(ctx context.Context, userID, otherUserID string) error
query.Set("otherUser", otherUserID) query.Set("otherUser", otherUserID)
URL.RawQuery = query.Encode() URL.RawQuery = query.Encode()
err = c.doWithAuthToken(ctx, httpReq, nil) err = c.doWithAuthToken(ctx, httpReq, nil, authToken)
if err != nil { if err != nil {
return err return err
} }

View File

@ -27,7 +27,7 @@ const (
// CreateBot - Create a bot. See the Bots Tutorial (https://dev.groupme.com/tutorials/bots) // CreateBot - Create a bot. See the Bots Tutorial (https://dev.groupme.com/tutorials/bots)
// for a full walkthrough. // for a full walkthrough.
func (c *Client) CreateBot(ctx context.Context, bot *Bot) (*Bot, error) { func (c *Client) CreateBot(ctx context.Context, bot *Bot, authToken string) (*Bot, error) {
URL := c.endpointBase + createBotEndpoint URL := c.endpointBase + createBotEndpoint
var data = struct { var data = struct {
@ -47,7 +47,7 @@ func (c *Client) CreateBot(ctx context.Context, bot *Bot) (*Bot, error) {
} }
var resp Bot var resp Bot
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -84,14 +84,14 @@ func (c *Client) PostBotMessage(ctx context.Context, botID ID, text string, pict
} }
// IndexBots - list bots that you have created // IndexBots - list bots that you have created
func (c *Client) IndexBots(ctx context.Context) ([]*Bot, error) { func (c *Client) IndexBots(ctx context.Context, authToken string) ([]*Bot, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexBotsEndpoint, nil) httpReq, err := http.NewRequest("GET", c.endpointBase+indexBotsEndpoint, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var resp []*Bot var resp []*Bot
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -100,7 +100,7 @@ func (c *Client) IndexBots(ctx context.Context) ([]*Bot, error) {
} }
// DestroyBot - Remove a bot that you have created // DestroyBot - Remove a bot that you have created
func (c *Client) DestroyBot(ctx context.Context, botID ID) error { func (c *Client) DestroyBot(ctx context.Context, botID ID, authToken string) error {
URL := fmt.Sprintf(c.endpointBase + destroyBotEndpoint) URL := fmt.Sprintf(c.endpointBase + destroyBotEndpoint)
var data = struct { var data = struct {
@ -119,5 +119,5 @@ func (c *Client) DestroyBot(ctx context.Context, botID ID) error {
return err return err
} }
return c.doWithAuthToken(ctx, httpReq, nil) return c.doWithAuthToken(ctx, httpReq, nil, authToken)
} }

View File

@ -27,7 +27,7 @@ type IndexChatsQuery struct {
// IndexChats - Returns a paginated list of direct message chats, or // IndexChats - Returns a paginated list of direct message chats, or
// conversations, sorted by updated_at descending. // conversations, sorted by updated_at descending.
func (c *Client) IndexChats(ctx context.Context, req *IndexChatsQuery) ([]*Chat, error) { func (c *Client) IndexChats(ctx context.Context, req *IndexChatsQuery, authToken string) ([]*Chat, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexChatsEndpoint, nil) httpReq, err := http.NewRequest("GET", c.endpointBase+indexChatsEndpoint, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -46,7 +46,27 @@ func (c *Client) IndexChats(ctx context.Context, req *IndexChatsQuery) ([]*Chat,
URL.RawQuery = query.Encode() URL.RawQuery = query.Encode()
var resp []*Chat var resp []*Chat
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
return resp, nil
}
func (c *Client) IndexRelations(ctx context.Context, authToken string) ([]*User, error) {
httpReq, err := http.NewRequest("GET", "https://api.groupme.com/v4"+"/relationships", nil)
if err != nil {
return nil, err
}
URL := httpReq.URL
query := URL.Query()
query.Set("include_blocked", "true")
URL.RawQuery = query.Encode()
var resp []*User
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -18,16 +18,14 @@ const GroupMeAPIBase = "https://api.groupme.com/v3"
type Client struct { type Client struct {
httpClient *http.Client httpClient *http.Client
endpointBase string endpointBase string
authorizationToken string
} }
// NewClient creates a new GroupMe API Client // NewClient creates a new GroupMe API Client
func NewClient(authToken string) *Client { func NewClient() *Client {
return &Client{ return &Client{
// TODO: enable transport information passing in // TODO: enable transport information passing in
httpClient: &http.Client{}, httpClient: &http.Client{},
endpointBase: GroupMeAPIBase, endpointBase: GroupMeAPIBase,
authorizationToken: authToken,
} }
} }
@ -112,10 +110,10 @@ func (c Client) do(ctx context.Context, req *http.Request, i interface{}) error
return nil return nil
} }
func (c Client) doWithAuthToken(ctx context.Context, req *http.Request, i interface{}) error { func (c Client) doWithAuthToken(ctx context.Context, req *http.Request, i interface{}, authToken string) error {
URL := req.URL URL := req.URL
query := URL.Query() query := URL.Query()
query.Set("token", c.authorizationToken) query.Set("token", authToken)
URL.RawQuery = query.Encode() URL.RawQuery = query.Encode()
return c.do(ctx, req, i) return c.do(ctx, req, i)

View File

@ -63,10 +63,11 @@ Note that for historical reasons, likes are returned as an array
of user ids in the favorited_by key. of user ids in the favorited_by key.
Parameters: Parameters:
otherUserID - required, ID(string); the other participant in the conversation. otherUserID - required, ID(string); the other participant in the conversation.
See IndexDirectMessagesQuery See IndexDirectMessagesQuery
*/ */
func (c *Client) IndexDirectMessages(ctx context.Context, otherUserID string, req *IndexDirectMessagesQuery) (IndexDirectMessagesResponse, error) { func (c *Client) IndexDirectMessages(ctx context.Context, otherUserID string, req *IndexDirectMessagesQuery, authToken string) (IndexDirectMessagesResponse, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexDirectMessagesEndpoint, nil) httpReq, err := http.NewRequest("GET", c.endpointBase+indexDirectMessagesEndpoint, nil)
if err != nil { if err != nil {
return IndexDirectMessagesResponse{}, err return IndexDirectMessagesResponse{}, err
@ -82,9 +83,10 @@ func (c *Client) IndexDirectMessages(ctx context.Context, otherUserID string, re
query.Add("since_id", req.SinceID.String()) query.Add("since_id", req.SinceID.String())
} }
} }
httpReq.URL.RawQuery = query.Encode()
var resp IndexDirectMessagesResponse var resp IndexDirectMessagesResponse
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return IndexDirectMessagesResponse{}, err return IndexDirectMessagesResponse{}, err
} }
@ -106,7 +108,7 @@ specify a replacement charmap to substitute emoji characters
The character map is an array of arrays containing rune data The character map is an array of arrays containing rune data
([[{pack_id,offset}],...]). ([[{pack_id,offset}],...]).
*/ */
func (c *Client) CreateDirectMessage(ctx context.Context, m *Message) (*Message, error) { func (c *Client) CreateDirectMessage(ctx context.Context, m *Message, authToken string) (*Message, error) {
URL := fmt.Sprintf(c.endpointBase + createDirectMessageEndpoint) URL := fmt.Sprintf(c.endpointBase + createDirectMessageEndpoint)
m.SourceGUID = uuid.New().String() m.SourceGUID = uuid.New().String()
@ -127,9 +129,9 @@ func (c *Client) CreateDirectMessage(ctx context.Context, m *Message) (*Message,
} }
var resp struct { var resp struct {
*Message `json:"message"` *Message `json:"direct_message"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,8 +3,6 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/densestvoid/groupme"
) )
// This is not a real token. Please find yours by logging // This is not a real token. Please find yours by logging

View File

@ -3,8 +3,6 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/densestvoid/groupme"
) )
// This is not a real Bot ID. Please find yours by logging // This is not a real Bot ID. Please find yours by logging

View File

@ -0,0 +1,177 @@
package main
import (
"context"
"fmt"
"log"
"gitea.watsonlabs.net/watsonb8/groupme-lib"
)
// This is not a real token. Please find yours by logging
// into the GroupMe development website: https://dev.groupme.com/
var authorizationToken = "ASD"
var authorizationToken2 = "ASDF"
// A short program that subscribes to 2 groups and 2 direct chats
// and prints out all recognized events in those
func main() {
//create push subscription and start listening
p := groupme.NewPushSubscription(context.Background())
err := p.Connect(context.TODO())
if err != nil {
return
}
// Create a new client with your auth token
client := groupme.NewClient()
User, _ := client.MyUser(context.Background(), authorizationToken)
User2, _ := client.MyUser(context.Background(), authorizationToken2)
//handles (in this case prints) all messages
p.AddFullHandler(Handler{User: User}, authorizationToken)
p.AddHandler(Handler{User: User2}, authorizationToken2)
//Subscribe to get messages and events for the specific user
p.SubscribeToUser(context.Background(), User.ID, authorizationToken)
p.SubscribeToUser(context.Background(), User2.ID, authorizationToken2)
if err != nil {
log.Fatal(err)
}
// Get the groups your user is part of
groups, err := client.IndexGroups(
context.Background(),
&groupme.GroupsQuery{
Page: 0,
PerPage: 2,
Omit: "memberships",
}, authorizationToken)
groups2, err := client.IndexGroups(
context.Background(),
&groupme.GroupsQuery{
Page: 0,
PerPage: 2,
Omit: "memberships",
}, authorizationToken2)
if err != nil {
fmt.Println(err)
return
}
//Subscribe to those groups
for _, j := range groups {
err = p.SubscribeToGroup(context.TODO(), j.ID, authorizationToken)
if err != nil {
log.Fatal(err)
}
}
for _, j := range groups2 {
err = p.SubscribeToGroup(context.TODO(), j.ID, authorizationToken2)
if err != nil {
log.Fatal(err)
}
}
//get chats your user is part of
chats, err := client.IndexChats(context.Background(),
&groupme.IndexChatsQuery{
Page: 0,
PerPage: 2,
}, authorizationToken)
chats2, err := client.IndexChats(context.Background(),
&groupme.IndexChatsQuery{
Page: 0,
PerPage: 2,
}, authorizationToken2)
//subscribe to all those chats
for _, j := range chats {
go func() {
err := p.SubscribeToDM(context.TODO(), j.LastMessage.ConversationID, authorizationToken)
if err != nil {
log.Fatal(err)
}
}()
}
for _, j := range chats2 {
go func() {
err := p.SubscribeToDM(context.TODO(), j.LastMessage.ConversationID, authorizationToken2)
if err != nil {
log.Fatal(err)
}
}()
}
//blocking
<-make(chan (struct{}))
}
// Following example handlers print out all data
type Handler struct {
User *groupme.User
}
func (h Handler) HandleError(e error) {
fmt.Println(e)
}
func (h Handler) HandleTextMessage(msg groupme.Message) {
fmt.Println(msg.Text, msg.Name, msg.Attachments)
}
func (h Handler) HandleJoin(group groupme.ID) {
fmt.Println("User joined group with id", group.String())
}
func (h Handler) HandleLike(msg groupme.Message) {
fmt.Println(msg.ID, "liked by", msg.FavoritedBy)
}
func (h Handler) HandlerMembership(i groupme.ID) {
fmt.Println("Membership event on", i.String())
}
func (h Handler) HandleGroupTopic(group groupme.ID, newTopic string) {
fmt.Println(group.String(), "has new topic of", newTopic)
}
func (h Handler) HandleGroupName(group groupme.ID, newName string) {
fmt.Println(group.String(), "has new name of", newName)
}
func (h Handler) HandleGroupAvatar(group groupme.ID, newAvatar string) {
fmt.Println(group.String(), "has new avatar url of", newAvatar)
}
func (h Handler) HandleLikeIcon(group groupme.ID, PackID, PackIndex int, Type string) {
//Not sure how to use without groupme icon packs
if len(Type) == 0 {
fmt.Println("Default like icon set")
return
}
fmt.Println(group.String(), "has new like icon of", PackID, PackIndex, Type)
}
func (h Handler) HandleNewNickname(group groupme.ID, user groupme.ID, newName string) {
fmt.Printf("In group %s, user %s has new nickname %s\n", group.String(), user.String(), newName)
}
func (h Handler) HandleNewAvatarInGroup(group groupme.ID, user groupme.ID, avatarURL string) {
if avatarURL == "" {
//get default avatar
avatarURL = h.User.ImageURL
}
fmt.Printf("In group %s, user %s has new avatar with url %s\n", group.String(), user.String(), avatarURL)
}
func (h Handler) HandleMembers(group groupme.ID, members []groupme.Member, added bool) {
action := "removed"
if added {
action = "added"
}
fmt.Printf("In group %s, users %v %s\n", group.String(), members, action)
}

12
go.mod
View File

@ -1,9 +1,17 @@
module github.com/densestvoid/groupme module gitea.watsonlabs.net/watsonb8/groupme-lib
go 1.15 go 1.21.0
require ( require (
gitea.watsonlabs.net/watsonb8/fayec v0.0.5-0.20230926180210-b375ab3c8c11
github.com/google/uuid v1.2.0 github.com/google/uuid v1.2.0
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
) )
require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

36
go.sum
View File

@ -1,15 +1,49 @@
gitea.watsonlabs.net/watsonb8/fayec v0.0.0-20230919020138-8f0db7048755 h1:FEhNSjSNvZ+nVg5Z3ds6X8ys3qjM+mmyLTSqKhCUHuQ=
gitea.watsonlabs.net/watsonb8/fayec v0.0.0-20230919020138-8f0db7048755/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.0-20230919151904-5ca9ade6f946 h1:loc70tiaFs1U4sqn+lKMSBlo5OfvVfClYnWjfGLXaSg=
gitea.watsonlabs.net/watsonb8/fayec v0.0.0-20230919151904-5ca9ade6f946/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.1 h1:MNFmTaTyyKKgrw04dGO9C5ojtm1jIvy8oHYqbj0ECeY=
gitea.watsonlabs.net/watsonb8/fayec v0.0.1/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.2 h1:tqbgr1vRZ6Wq4W81xBg+FTOywSv3EJpK263SAVXXTco=
gitea.watsonlabs.net/watsonb8/fayec v0.0.2/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.3 h1:YpaZBIee8Ix6uGm1UoEtBix1dEU1TURChAsJGJ3pVRo=
gitea.watsonlabs.net/watsonb8/fayec v0.0.3/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.4 h1:SLvwip1DQy13QngVsEgoLtN7T6bS+X6348p6PQhUF2A=
gitea.watsonlabs.net/watsonb8/fayec v0.0.4/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.5-0.20230926180210-b375ab3c8c11 h1:xJ9eSFyIrDA43UVpbxOD1QkA2jhg+vS+eezFKCDV3Dw=
gitea.watsonlabs.net/watsonb8/fayec v0.0.5-0.20230926180210-b375ab3c8c11/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.5 h1:9+UHzUuEcLuZ5Gx5S/NTBxYshUhsiQ5M3vzUF8RAKxw=
gitea.watsonlabs.net/watsonb8/fayec v0.0.5/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
github.com/autogrowsystems/wray v0.0.0-20160519030252-f36984f6648c/go.mod h1:druJ8QMeBCUmwJ7ZSFowx77dWxEWF3SYlQlsqZaLZQg=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/karmanyaahm/wray v0.0.0-20210303233435-756d58657c14 h1:NrATjZKvkY+ojL8FXTWa3fQ+wihFrAxLNE6T+wOkIcY=
github.com/karmanyaahm/wray v0.0.0-20210303233435-756d58657c14/go.mod h1:ysD86MIEevmAkdfdg5s6Qt3I07RN6fvMAyna7jCGG2o=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

View File

@ -86,7 +86,7 @@ app for users who are participating in huge groups.
Parameters: See GroupsQuery Parameters: See GroupsQuery
*/ */
func (c *Client) IndexGroups(ctx context.Context, req *GroupsQuery) ([]*Group, error) { func (c *Client) IndexGroups(ctx context.Context, req *GroupsQuery, authToken string) ([]*Group, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexGroupsEndpoint, nil) httpReq, err := http.NewRequest("GET", c.endpointBase+indexGroupsEndpoint, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -108,7 +108,7 @@ func (c *Client) IndexGroups(ctx context.Context, req *GroupsQuery) ([]*Group, e
URL.RawQuery = query.Encode() URL.RawQuery = query.Encode()
var resp []*Group var resp []*Group
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -123,14 +123,14 @@ FormerGroups -
List they groups you have left but can rejoin. List they groups you have left but can rejoin.
*/ */
func (c *Client) FormerGroups(ctx context.Context) ([]*Group, error) { func (c *Client) FormerGroups(ctx context.Context, authToken string) ([]*Group, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+formerGroupsEndpoint, nil) httpReq, err := http.NewRequest("GET", c.endpointBase+formerGroupsEndpoint, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var resp []*Group var resp []*Group
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -146,9 +146,10 @@ ShowGroup -
Loads a specific group. Loads a specific group.
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
*/ */
func (c *Client) ShowGroup(ctx context.Context, groupID ID) (*Group, error) { func (c *Client) ShowGroup(ctx context.Context, groupID ID, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase+showGroupEndpoint, groupID) URL := fmt.Sprintf(c.endpointBase+showGroupEndpoint, groupID)
httpReq, err := http.NewRequest("GET", URL, nil) httpReq, err := http.NewRequest("GET", URL, nil)
@ -157,7 +158,7 @@ func (c *Client) ShowGroup(ctx context.Context, groupID ID) (*Group, error) {
} }
var resp Group var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -170,11 +171,11 @@ func (c *Client) ShowGroup(ctx context.Context, groupID ID) (*Group, error) {
/* /*
CreateGroup - CreateGroup -
Create a new group # Create a new group
Parameters: See GroupSettings Parameters: See GroupSettings
*/ */
func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings) (*Group, error) { func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase + createGroupEndpoint) URL := fmt.Sprintf(c.endpointBase + createGroupEndpoint)
jsonBytes, err := json.Marshal(&gs) jsonBytes, err := json.Marshal(&gs)
@ -188,7 +189,7 @@ func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings) (*Group, err
} }
var resp Group var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -201,13 +202,14 @@ func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings) (*Group, err
/* /*
UpdateGroup - UpdateGroup -
Update a group after creation # Update a group after creation
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
See GroupSettings See GroupSettings
*/ */
func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings) (*Group, error) { func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase+updateGroupEndpoint, groupID) URL := fmt.Sprintf(c.endpointBase+updateGroupEndpoint, groupID)
jsonBytes, err := json.Marshal(&gs) jsonBytes, err := json.Marshal(&gs)
@ -221,7 +223,7 @@ func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings)
} }
var resp Group var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -234,14 +236,15 @@ func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings)
/* /*
DestroyGroup - DestroyGroup -
Disband a group # Disband a group
This action is only available to the group creator # This action is only available to the group creator
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
*/ */
func (c *Client) DestroyGroup(ctx context.Context, groupID ID) error { func (c *Client) DestroyGroup(ctx context.Context, groupID ID, authToken string) error {
url := fmt.Sprintf(c.endpointBase+destroyGroupEndpoint, groupID) url := fmt.Sprintf(c.endpointBase+destroyGroupEndpoint, groupID)
httpReq, err := http.NewRequest("POST", url, nil) httpReq, err := http.NewRequest("POST", url, nil)
@ -249,7 +252,7 @@ func (c *Client) DestroyGroup(ctx context.Context, groupID ID) error {
return err return err
} }
return c.doWithAuthToken(ctx, httpReq, nil) return c.doWithAuthToken(ctx, httpReq, nil, authToken)
} }
/*/// Join ///*/ /*/// Join ///*/
@ -257,13 +260,14 @@ func (c *Client) DestroyGroup(ctx context.Context, groupID ID) error {
/* /*
JoinGroup - JoinGroup -
Join a shared group # Join a shared group
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
shareToken - required, string shareToken - required, string
*/ */
func (c *Client) JoinGroup(ctx context.Context, groupID ID, shareToken string) (*Group, error) { func (c *Client) JoinGroup(ctx context.Context, groupID ID, shareToken string, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase+joinGroupEndpoint, groupID, shareToken) URL := fmt.Sprintf(c.endpointBase+joinGroupEndpoint, groupID, shareToken)
httpReq, err := http.NewRequest("POST", URL, nil) httpReq, err := http.NewRequest("POST", URL, nil)
@ -272,7 +276,7 @@ func (c *Client) JoinGroup(ctx context.Context, groupID ID, shareToken string) (
} }
var resp Group var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -288,9 +292,10 @@ RejoinGroup -
Rejoin a group. Only works if you previously removed yourself. Rejoin a group. Only works if you previously removed yourself.
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
*/ */
func (c *Client) RejoinGroup(ctx context.Context, groupID ID) (*Group, error) { func (c *Client) RejoinGroup(ctx context.Context, groupID ID, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase + rejoinGroupEndpoint) URL := fmt.Sprintf(c.endpointBase + rejoinGroupEndpoint)
var data = struct { var data = struct {
@ -310,7 +315,7 @@ func (c *Client) RejoinGroup(ctx context.Context, groupID ID) (*Group, error) {
} }
var resp Group var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -330,7 +335,7 @@ the result of change owner action for the request
Parameters: See ChangeOwnerRequest Parameters: See ChangeOwnerRequest
*/ */
func (c *Client) ChangeGroupOwner(ctx context.Context, reqs ChangeOwnerRequest) (ChangeOwnerResult, error) { func (c *Client) ChangeGroupOwner(ctx context.Context, reqs ChangeOwnerRequest, authToken string) (ChangeOwnerResult, error) {
URL := fmt.Sprintf(c.endpointBase + changeGroupOwnerEndpoint) URL := fmt.Sprintf(c.endpointBase + changeGroupOwnerEndpoint)
var data = struct { var data = struct {
@ -353,7 +358,7 @@ func (c *Client) ChangeGroupOwner(ctx context.Context, reqs ChangeOwnerRequest)
Results []ChangeOwnerResult `json:"results"` Results []ChangeOwnerResult `json:"results"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return ChangeOwnerResult{}, err return ChangeOwnerResult{}, err
} }

View File

@ -111,6 +111,8 @@ type Message struct {
System bool `json:"system,omitempty"` System bool `json:"system,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
RecipientID ID `json:"recipient_id,omitempty"` RecipientID ID `json:"recipient_id,omitempty"`
//ChatID - over push ConversationID seems to be called ChatID
ChatID ID `json:"chat_id,omitempty"`
ConversationID ID `json:"conversation_id,omitempty"` ConversationID ID `json:"conversation_id,omitempty"`
AvatarURL string `json:"avatar_url,omitempty"` AvatarURL string `json:"avatar_url,omitempty"`
// Maximum length of 1000 characters // Maximum length of 1000 characters
@ -150,11 +152,14 @@ type Attachment struct {
Loci [][]int `json:"loci,omitempty"` Loci [][]int `json:"loci,omitempty"`
UserIDs []ID `json:"user_ids,omitempty"` UserIDs []ID `json:"user_ids,omitempty"`
URL string `json:"url,omitempty"` URL string `json:"url,omitempty"`
FileID string `json:"file_id,omitempty"`
VideoPreviewURL string `json:"preview_url,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Latitude string `json:"lat,omitempty"` Latitude string `json:"lat,omitempty"`
Longitude string `json:"lng,omitempty"` Longitude string `json:"lng,omitempty"`
Placeholder string `json:"placeholder,omitempty"` Placeholder string `json:"placeholder,omitempty"`
Charmap [][]int `json:"charmap,omitempty"` Charmap [][]int `json:"charmap,omitempty"`
ReplyID ID `json:"reply_id,omitempty"`
} }
func (a *Attachment) String() string { func (a *Attachment) String() string {

View File

@ -35,7 +35,7 @@ const (
// IndexLeaderboard - A list of the liked messages in the group for a given period of // IndexLeaderboard - A list of the liked messages in the group for a given period of
// time. Messages are ranked in order of number of likes. // time. Messages are ranked in order of number of likes.
func (c *Client) IndexLeaderboard(ctx context.Context, groupID ID, p period) ([]*Message, error) { func (c *Client) IndexLeaderboard(ctx context.Context, groupID ID, p period, authToken string) ([]*Message, error) {
url := fmt.Sprintf(c.endpointBase+indexLeaderboardEndpoint, groupID) url := fmt.Sprintf(c.endpointBase+indexLeaderboardEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil) httpReq, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
@ -50,7 +50,7 @@ func (c *Client) IndexLeaderboard(ctx context.Context, groupID ID, p period) ([]
var resp struct { var resp struct {
Messages []*Message `json:"messages"` Messages []*Message `json:"messages"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -68,9 +68,10 @@ reverse chrono-order. Note that the payload includes a liked_at
timestamp in ISO-8601 format. timestamp in ISO-8601 format.
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
*/ */
func (c *Client) MyLikesLeaderboard(ctx context.Context, groupID ID) ([]*Message, error) { func (c *Client) MyLikesLeaderboard(ctx context.Context, groupID ID, authToken string) ([]*Message, error) {
url := fmt.Sprintf(c.endpointBase+myLikesLeaderboardEndpoint, groupID) url := fmt.Sprintf(c.endpointBase+myLikesLeaderboardEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil) httpReq, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
@ -80,7 +81,7 @@ func (c *Client) MyLikesLeaderboard(ctx context.Context, groupID ID) ([]*Message
var resp struct { var resp struct {
Messages []*Message `json:"messages"` Messages []*Message `json:"messages"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -98,9 +99,10 @@ reverse chrono-order. Note that the payload includes a liked_at
timestamp in ISO-8601 format. timestamp in ISO-8601 format.
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
*/ */
func (c *Client) MyHitsLeaderboard(ctx context.Context, groupID ID) ([]*Message, error) { func (c *Client) MyHitsLeaderboard(ctx context.Context, groupID ID, authToken string) ([]*Message, error) {
url := fmt.Sprintf(c.endpointBase+myHitsLeaderboardEndpoint, groupID) url := fmt.Sprintf(c.endpointBase+myHitsLeaderboardEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil) httpReq, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
@ -110,7 +112,7 @@ func (c *Client) MyHitsLeaderboard(ctx context.Context, groupID ID) ([]*Message,
var resp struct { var resp struct {
Messages []*Message `json:"messages"` Messages []*Message `json:"messages"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -23,7 +23,7 @@ const (
// Create // Create
// CreateLike - Like a message. // CreateLike - Like a message.
func (c *Client) CreateLike(ctx context.Context, conversationID, messageID ID) error { func (c *Client) CreateLike(ctx context.Context, conversationID, messageID ID, authToken string) error {
url := fmt.Sprintf(c.endpointBase+createLikeEndpoint, conversationID, messageID) url := fmt.Sprintf(c.endpointBase+createLikeEndpoint, conversationID, messageID)
httpReq, err := http.NewRequest("POST", url, nil) httpReq, err := http.NewRequest("POST", url, nil)
@ -31,11 +31,11 @@ func (c *Client) CreateLike(ctx context.Context, conversationID, messageID ID) e
return err return err
} }
return c.doWithAuthToken(ctx, httpReq, nil) return c.doWithAuthToken(ctx, httpReq, nil, authToken)
} }
// DestroyLike - Unlike a message. // DestroyLike - Unlike a message.
func (c *Client) DestroyLike(ctx context.Context, conversationID, messageID ID) error { func (c *Client) DestroyLike(ctx context.Context, conversationID, messageID ID, authToken string) error {
url := fmt.Sprintf(c.endpointBase+destroyLikeEndpoint, conversationID, messageID) url := fmt.Sprintf(c.endpointBase+destroyLikeEndpoint, conversationID, messageID)
httpReq, err := http.NewRequest("POST", url, nil) httpReq, err := http.NewRequest("POST", url, nil)
@ -43,5 +43,5 @@ func (c *Client) DestroyLike(ctx context.Context, conversationID, messageID ID)
return err return err
} }
return c.doWithAuthToken(ctx, httpReq, nil) return c.doWithAuthToken(ctx, httpReq, nil, authToken)
} }

View File

@ -40,6 +40,7 @@ GUIDs can be added to the members parameters. These GUIDs will
be reflected in the membership JSON objects. be reflected in the membership JSON objects.
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
See Member. See Member.
Nickname - required Nickname - required
@ -48,7 +49,7 @@ Parameters:
PhoneNumber - PhoneNumber(string) PhoneNumber - PhoneNumber(string)
Email - string Email - string
*/ */
func (c *Client) AddMembers(ctx context.Context, groupID ID, members ...*Member) (string, error) { func (c *Client) AddMembers(ctx context.Context, groupID ID, authToken string, members ...*Member) (string, error) {
URL := fmt.Sprintf(c.endpointBase+addMembersEndpoint, groupID) URL := fmt.Sprintf(c.endpointBase+addMembersEndpoint, groupID)
var data = struct { var data = struct {
@ -71,7 +72,7 @@ func (c *Client) AddMembers(ctx context.Context, groupID ID, members ...*Member)
ResultsID string `json:"results_id"` ResultsID string `json:"results_id"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -94,10 +95,11 @@ Keep in mind that results are temporary -- they will only be
available for 1 hour after the add request. available for 1 hour after the add request.
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
resultID - required, string resultID - required, string
*/ */
func (c *Client) AddMembersResults(ctx context.Context, groupID ID, resultID string) ([]*Member, error) { func (c *Client) AddMembersResults(ctx context.Context, groupID ID, resultID string, authToken string) ([]*Member, error) {
URL := fmt.Sprintf(c.endpointBase+addMembersResultsEndpoint, groupID, resultID) URL := fmt.Sprintf(c.endpointBase+addMembersResultsEndpoint, groupID, resultID)
httpReq, err := http.NewRequest("GET", URL, nil) httpReq, err := http.NewRequest("GET", URL, nil)
@ -109,7 +111,7 @@ func (c *Client) AddMembersResults(ctx context.Context, groupID ID, resultID str
Members []*Member `json:"members"` Members []*Member `json:"members"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -127,10 +129,11 @@ Remove a member (or yourself) from a group.
Note: The creator of the group cannot be removed or exit. Note: The creator of the group cannot be removed or exit.
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
membershipID - required, ID(string). Not the same as userID membershipID - required, ID(string). Not the same as userID
*/ */
func (c *Client) RemoveMember(ctx context.Context, groupID, membershipID ID) error { func (c *Client) RemoveMember(ctx context.Context, groupID, membershipID ID, authToken string) error {
URL := fmt.Sprintf(c.endpointBase+removeMemberEndpoint, groupID, membershipID) URL := fmt.Sprintf(c.endpointBase+removeMemberEndpoint, groupID, membershipID)
httpReq, err := http.NewRequest("POST", URL, nil) httpReq, err := http.NewRequest("POST", URL, nil)
@ -138,7 +141,7 @@ func (c *Client) RemoveMember(ctx context.Context, groupID, membershipID ID) err
return err return err
} }
return c.doWithAuthToken(ctx, httpReq, nil) return c.doWithAuthToken(ctx, httpReq, nil, authToken)
} }
/*/// Update ///*/ /*/// Update ///*/
@ -149,7 +152,7 @@ UpdateMember -
Update your nickname in a group. The nickname must be Update your nickname in a group. The nickname must be
between 1 and 50 characters. between 1 and 50 characters.
*/ */
func (c *Client) UpdateMember(ctx context.Context, groupID ID, nickname string) (*Member, error) { func (c *Client) UpdateMember(ctx context.Context, groupID ID, nickname string, authToken string) (*Member, error) {
URL := fmt.Sprintf(c.endpointBase+updateMemberEndpoint, groupID) URL := fmt.Sprintf(c.endpointBase+updateMemberEndpoint, groupID)
type Nickname struct { type Nickname struct {
@ -173,7 +176,7 @@ func (c *Client) UpdateMember(ctx context.Context, groupID ID, nickname string)
var resp Member var resp Member
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -75,7 +75,7 @@ we return code 304.
Note that for historical reasons, likes are returned as an Note that for historical reasons, likes are returned as an
array of user ids in the favorited_by key. array of user ids in the favorited_by key.
*/ */
func (c *Client) IndexMessages(ctx context.Context, groupID ID, req *IndexMessagesQuery) (IndexMessagesResponse, error) { func (c *Client) IndexMessages(ctx context.Context, groupID ID, req *IndexMessagesQuery, authToken string) (IndexMessagesResponse, error) {
url := fmt.Sprintf(c.endpointBase+indexMessagesEndpoint, groupID) url := fmt.Sprintf(c.endpointBase+indexMessagesEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil) httpReq, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
@ -101,7 +101,7 @@ func (c *Client) IndexMessages(ctx context.Context, groupID ID, req *IndexMessag
URL.RawQuery = query.Encode() URL.RawQuery = query.Encode()
var resp IndexMessagesResponse var resp IndexMessagesResponse
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return IndexMessagesResponse{}, err return IndexMessagesResponse{}, err
} }
@ -125,7 +125,7 @@ The character map is an array of arrays containing rune data
The placeholder should be a high-point/invisible UTF-8 character. The placeholder should be a high-point/invisible UTF-8 character.
*/ */
func (c *Client) CreateMessage(ctx context.Context, groupID ID, m *Message) (*Message, error) { func (c *Client) CreateMessage(ctx context.Context, groupID ID, m *Message, authToken string) (*Message, error) {
URL := fmt.Sprintf(c.endpointBase+createMessagesEndpoint, groupID) URL := fmt.Sprintf(c.endpointBase+createMessagesEndpoint, groupID)
m.SourceGUID = uuid.New().String() m.SourceGUID = uuid.New().String()
@ -148,7 +148,7 @@ func (c *Client) CreateMessage(ctx context.Context, groupID ID, m *Message) (*Me
var resp struct { var resp struct {
*Message `json:"message"` *Message `json:"message"`
} }
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }

196
real_time.go Normal file
View File

@ -0,0 +1,196 @@
package groupme
import (
"context"
"errors"
"gitea.watsonlabs.net/watsonb8/fayec"
"gitea.watsonlabs.net/watsonb8/fayec/message"
"gitea.watsonlabs.net/watsonb8/fayec/subscription"
"log"
"strings"
"sync"
"time"
)
const (
PushServer = "wss://push.groupme.com/faye"
userChannel = "/user/"
groupChannel = "/group/"
dmChannel = "/direct_message/"
)
var (
ErrHandlerNotFound = errors.New("Handler not found")
ErrListenerNotStarted = errors.New("GroupMe listener not started")
)
var concur = sync.Mutex{}
type HandlerAll interface {
Handler
//of self
HandlerText
HandlerLike
HandlerMembership
//of group
HandleGroupTopic
HandleGroupAvatar
HandleGroupName
HandleGroupLikeIcon
//of group members
HandleMemberNewNickname
HandleMemberNewAvatar
HandleMembers
}
type Handler interface {
HandleError(error)
}
type HandlerText interface {
HandleTextMessage(Message)
}
type HandlerLike interface {
HandleLike(Message)
}
type HandlerMembership interface {
HandleJoin(ID)
}
// Group Handlers
type HandleGroupTopic interface {
HandleGroupTopic(group ID, newTopic string)
}
type HandleGroupName interface {
HandleGroupName(group ID, newName string)
}
type HandleGroupAvatar interface {
HandleGroupAvatar(group ID, newAvatar string)
}
type HandleGroupLikeIcon interface {
HandleLikeIcon(group ID, PackID, PackIndex int, Type string)
}
// Group member handlers
type HandleMemberNewNickname interface {
HandleNewNickname(group ID, user ID, newName string)
}
type HandleMemberNewAvatar interface {
HandleNewAvatarInGroup(group ID, user ID, avatarURL string)
}
type HandleMembers interface {
//HandleNewMembers returns only partial member with id and nickname; added is false if removing
HandleMembers(group ID, members []Member, added bool)
}
// PushSubscription manages real time subscription
type PushSubscription struct {
channel chan message.Data
client *fayec.Client
handlers map[string][]Handler // key == token
LastConnected int64
}
// NewPushSubscription creates and returns a push subscription object
func NewPushSubscription(context context.Context) PushSubscription {
r := PushSubscription{
channel: make(chan message.Data),
handlers: make(map[string][]Handler),
}
return r
}
func (r *PushSubscription) AddHandler(h Handler, authToken string) {
if r.handlers[authToken] == nil {
r.handlers[authToken] = []Handler{h}
} else {
r.handlers[authToken] = append(r.handlers[authToken], h)
}
//r.handlers = append(r.handlers, h)
}
// AddFullHandler is the same as AddHandler except it ensures the interface implements everything
func (r *PushSubscription) AddFullHandler(h HandlerAll, authToken string) {
if r.handlers[authToken] == nil {
r.handlers[authToken] = []Handler{h}
} else {
r.handlers[authToken] = append(r.handlers[authToken], h)
}
//r.handlers = append(r.handlers, h)
}
var RealTimeHandlers map[string]func(r *PushSubscription, channel string, authToken string, data ...interface{})
var RealTimeSystemHandlers map[string]func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte)
// Listen connects to GroupMe. Runs in Goroutine.
func (r *PushSubscription) Connect(context context.Context) error {
c, err := fayec.NewClient(PushServer)
if err != nil {
return err
}
r.client = c
return nil
}
// SubscribeToUser to users
func (r *PushSubscription) SubscribeToUser(context context.Context, id ID, authToken string) error {
return r.subscribeWithPrefix(userChannel, context, id, authToken)
}
// SubscribeToGroup to groups for typing notification
func (r *PushSubscription) SubscribeToGroup(context context.Context, id ID, authToken string) error {
return r.subscribeWithPrefix(groupChannel, context, id, authToken)
}
// SubscribeToDM to users
func (r *PushSubscription) SubscribeToDM(context context.Context, id ID, authToken string) error {
id = ID(strings.Replace(id.String(), "+", "_", 1))
return r.subscribeWithPrefix(dmChannel, context, id, authToken)
}
func (r *PushSubscription) subscribeWithPrefix(prefix string, context context.Context, groupID ID, authToken string) error {
concur.Lock()
defer concur.Unlock()
if r.client == nil {
return ErrListenerNotStarted
}
var sub *subscription.Subscription
sub, err := r.client.Subscribe(prefix+groupID.String(), authToken)
if err != nil {
panic(err)
}
err = sub.OnMessage(func(channel string, data message.Data) {
r.LastConnected = time.Now().Unix()
dataMap := data.(map[string]interface{})
content := dataMap["subject"]
contentType := dataMap["type"].(string)
handler, ok := RealTimeHandlers[contentType]
if !ok {
if contentType == "ping" ||
len(contentType) == 0 ||
content == "" {
return
}
log.Println("Unable to handle GroupMe message type", contentType)
} else {
handler(r, channel, authToken, content)
}
})
return nil
}
// Connected check if connected
func (r *PushSubscription) Connected() bool {
return r.LastConnected+30 >= time.Now().Unix()
}

266
real_time_handler.go Normal file
View File

@ -0,0 +1,266 @@
package groupme
import (
"encoding/json"
"fmt"
"log"
"strconv"
)
func init() {
RealTimeHandlers = make(map[string]func(r *PushSubscription, channel string, authToken string, data ...interface{}))
//Base Handlers on user channel
RealTimeHandlers["direct_message.create"] = func(r *PushSubscription, channel string, authToken string, data ...interface{}) {
b, _ := json.Marshal(data[0])
out := Message{}
_ = json.Unmarshal(b, &out)
//maybe something with API versioning
out.ConversationID = out.ChatID
if out.UserID.String() == "system" {
event := struct {
Event struct {
Kind string `json:"type"`
Data interface{}
}
}{}
err := json.Unmarshal(b, &event)
if err != nil {
fmt.Println(err)
}
rawData, _ := json.Marshal(event.Event.Data)
handler, ok := RealTimeSystemHandlers[event.Event.Kind]
if !ok {
log.Println("Unable to handle system message of type", event.Event.Kind)
return
}
id := out.GroupID
if len(id) == 0 {
id = out.ConversationID
}
handler(r, channel, id, authToken, rawData)
return
}
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandlerText); ok {
h.HandleTextMessage(out)
}
}
}
RealTimeHandlers["line.create"] = RealTimeHandlers["direct_message.create"]
RealTimeHandlers["like.create"] = func(r *PushSubscription, channel string, authToken string, data ...interface{}) { //should be an associated chatEvent
}
RealTimeHandlers["membership.create"] = func(r *PushSubscription, channel string, authToken string, data ...interface{}) {
c, _ := data[0].(map[string]interface{})
id, _ := c["id"].(string)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandlerMembership); ok {
h.HandleJoin(ID(id))
}
}
}
//following are for each chat
RealTimeHandlers["favorite"] = func(r *PushSubscription, channel string, authToken string, data ...interface{}) {
c, ok := data[0].(map[string]interface{})
if !ok {
fmt.Println(data, "err")
return
}
e, ok := c["line"]
if !ok {
fmt.Println(data, "err")
return
}
d, _ := json.Marshal(e)
msg := Message{}
_ = json.Unmarshal(d, &msg)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandlerLike); ok {
h.HandleLike(msg)
}
}
}
//following are for messages from system (administrative/settings changes)
RealTimeSystemHandlers = make(map[string]func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte))
RealTimeSystemHandlers["membership.nickname_changed"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
thing := struct {
Name string
User struct {
ID int
}
}{}
_ = json.Unmarshal(rawData, &thing)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleMemberNewNickname); ok {
h.HandleNewNickname(id, ID(strconv.Itoa(thing.User.ID)), thing.Name)
}
}
}
RealTimeSystemHandlers["membership.avatar_changed"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
content := struct {
AvatarURL string `json:"avatar_url"`
User struct {
ID int
}
}{}
_ = json.Unmarshal(rawData, &content)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleMemberNewAvatar); ok {
h.HandleNewAvatarInGroup(id, ID(strconv.Itoa(content.User.ID)), content.AvatarURL)
}
}
}
RealTimeSystemHandlers["membership.announce.added"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Added []Member `json:"added_users"`
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleMembers); ok {
h.HandleMembers(id, data.Added, true)
}
}
}
RealTimeSystemHandlers["membership.notifications.removed"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Added Member `json:"removed_user"`
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleMembers); ok {
h.HandleMembers(id, []Member{data.Added}, false)
}
}
}
RealTimeSystemHandlers["membership.name_change"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Name string
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupName); ok {
h.HandleGroupName(id, data.Name)
}
}
}
RealTimeSystemHandlers["group.name_change"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Name string
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupName); ok {
h.HandleGroupName(id, data.Name)
}
}
}
RealTimeSystemHandlers["group.topic_change"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Topic string
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupTopic); ok {
h.HandleGroupTopic(id, data.Topic)
}
}
}
RealTimeSystemHandlers["group.avatar_change"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
AvatarURL string `json:"avatar_url"`
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupAvatar); ok {
h.HandleGroupAvatar(id, data.AvatarURL)
}
}
}
RealTimeSystemHandlers["group.like_icon_set"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
LikeIcon struct {
PackID int `json:"pack_id"`
PackIndex int `json:"pack_index"`
Type string
} `json:"like_icon"`
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupLikeIcon); ok {
h.HandleLikeIcon(id, data.LikeIcon.PackID, data.LikeIcon.PackIndex, data.LikeIcon.Type)
}
}
}
RealTimeSystemHandlers["group.like_icon_removed"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupLikeIcon); ok {
h.HandleLikeIcon(id, 0, 0, "")
}
}
}
}

View File

@ -31,13 +31,14 @@ Enables SMS mode for N hours, where N is at most 48. After N
hours have elapsed, user will receive push notfications. hours have elapsed, user will receive push notfications.
Parameters: Parameters:
duration - required, integer duration - required, integer
registration_id - string; The push notification ID/token registration_id - string; The push notification ID/token
that should be suppressed during SMS mode. If this is that should be suppressed during SMS mode. If this is
omitted, both SMS and push notifications will be omitted, both SMS and push notifications will be
delivered to the device. delivered to the device.
*/ */
func (c *Client) CreateSMSMode(ctx context.Context, duration int, registrationID *ID) error { func (c *Client) CreateSMSMode(ctx context.Context, duration int, registrationID *ID, authToken string) error {
URL := fmt.Sprintf(c.endpointBase + createSMSModeEndpoint) URL := fmt.Sprintf(c.endpointBase + createSMSModeEndpoint)
var data = struct { var data = struct {
@ -58,7 +59,7 @@ func (c *Client) CreateSMSMode(ctx context.Context, duration int, registrationID
return err return err
} }
err = c.doWithAuthToken(ctx, httpReq, nil) err = c.doWithAuthToken(ctx, httpReq, nil, authToken)
if err != nil { if err != nil {
return err return err
} }
@ -73,7 +74,7 @@ DeleteSMSMode -
Disables SMS mode Disables SMS mode
*/ */
func (c *Client) DeleteSMSMode(ctx context.Context) error { func (c *Client) DeleteSMSMode(ctx context.Context, authToken string) error {
url := fmt.Sprintf(c.endpointBase + deleteSMSModeEndpoint) url := fmt.Sprintf(c.endpointBase + deleteSMSModeEndpoint)
httpReq, err := http.NewRequest("POST", url, nil) httpReq, err := http.NewRequest("POST", url, nil)
@ -81,5 +82,5 @@ func (c *Client) DeleteSMSMode(ctx context.Context) error {
return err return err
} }
return c.doWithAuthToken(ctx, httpReq, nil) return c.doWithAuthToken(ctx, httpReq, nil, authToken)
} }

View File

@ -31,9 +31,10 @@ MyUser -
Loads a specific group. Loads a specific group.
Parameters: Parameters:
groupID - required, ID(string) groupID - required, ID(string)
*/ */
func (c *Client) MyUser(ctx context.Context) (*User, error) { func (c *Client) MyUser(ctx context.Context, authToken string) (*User, error) {
URL := fmt.Sprintf(c.endpointBase + myUserEndpoint) URL := fmt.Sprintf(c.endpointBase + myUserEndpoint)
httpReq, err := http.NewRequest("GET", URL, nil) httpReq, err := http.NewRequest("GET", URL, nil)
@ -42,7 +43,7 @@ func (c *Client) MyUser(ctx context.Context) (*User, error) {
} }
var resp User var resp User
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -65,11 +66,11 @@ type UserSettings struct {
/* /*
UpdateMyUser - UpdateMyUser -
Update attributes about your own account # Update attributes about your own account
Parameters: See UserSettings Parameters: See UserSettings
*/ */
func (c *Client) UpdateMyUser(ctx context.Context, us UserSettings) (*User, error) { func (c *Client) UpdateMyUser(ctx context.Context, us UserSettings, authToken string) (*User, error) {
URL := fmt.Sprintf(c.endpointBase + updateMyUserEndpoint) URL := fmt.Sprintf(c.endpointBase + updateMyUserEndpoint)
jsonBytes, err := json.Marshal(&us) jsonBytes, err := json.Marshal(&us)
@ -83,7 +84,7 @@ func (c *Client) UpdateMyUser(ctx context.Context, us UserSettings) (*User, erro
} }
var resp User var resp User
err = c.doWithAuthToken(ctx, httpReq, &resp) err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }