2021-01-22 21:47:22 +00:00
|
|
|
// Package groupme defines a client capable of executing API commands for the GroupMe chat service
|
2020-07-30 02:20:57 +00:00
|
|
|
package groupme
|
|
|
|
|
|
|
|
import (
|
2020-08-24 01:25:02 +00:00
|
|
|
"bytes"
|
2021-01-22 21:47:22 +00:00
|
|
|
"context"
|
2020-08-24 01:25:02 +00:00
|
|
|
"encoding/json"
|
2020-07-30 02:20:57 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
// GroupMe documentation: https://dev.groupme.com/docs/v3#groups
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*//////// Endpoints ////////*/
|
2020-07-30 02:20:57 +00:00
|
|
|
const (
|
|
|
|
// Used to build other endpoints
|
|
|
|
groupsEndpointRoot = "/groups"
|
|
|
|
groupEndpointRoot = "/groups/%s"
|
|
|
|
|
|
|
|
// Actual Endpoints
|
|
|
|
indexGroupsEndpoint = groupsEndpointRoot // GET
|
|
|
|
formerGroupsEndpoint = groupsEndpointRoot + "/former" // GET
|
|
|
|
showGroupEndpoint = groupEndpointRoot // GET
|
|
|
|
createGroupEndpoint = groupsEndpointRoot // POST
|
|
|
|
updateGroupEndpoint = groupEndpointRoot + "/update" // POST
|
|
|
|
destroyGroupEndpoint = groupEndpointRoot + "/destroy" // POST
|
|
|
|
joinGroupEndpoint = groupEndpointRoot + "/join/%s" // POST
|
|
|
|
rejoinGroupEndpoint = groupsEndpointRoot + "/join" // POST
|
|
|
|
changeGroupOwnerEndpoint = groupsEndpointRoot + "/change_owners" // POST
|
|
|
|
)
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*//////// Common Request Parameters ////////*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
// GroupSettings is the settings for a group, used by CreateGroup and UpdateGroup
|
|
|
|
type GroupSettings struct {
|
|
|
|
// Required. Primary name of the group. Maximum 140 characters
|
|
|
|
Name string `json:"name"`
|
|
|
|
// A subheading for the group. Maximum 255 characters
|
|
|
|
Description string `json:"description"`
|
|
|
|
// GroupMe Image Service URL
|
|
|
|
ImageURL string `json:"image_url"`
|
|
|
|
// Defaults false. If true, disables notifications for all members.
|
|
|
|
// Documented for use only for UpdateGroup
|
|
|
|
OfficeMode bool `json:"office_mode"`
|
|
|
|
// Defaults false. If true, generates a share URL.
|
|
|
|
// Anyone with the URL can join the group
|
|
|
|
Share bool `json:"share"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gss GroupSettings) String() string {
|
|
|
|
return marshal(&gss)
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*//////// API Requests ////////*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Index ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
// GroupsQuery defines optional URL parameters for IndexGroups
|
|
|
|
type GroupsQuery struct {
|
|
|
|
// Fetch a particular page of results. Defaults to 1.
|
|
|
|
Page int `json:"page"`
|
|
|
|
// Define page size. Defaults to 10.
|
|
|
|
PerPage int `json:"per_page"`
|
|
|
|
// Comma separated list of data to omit from output.
|
|
|
|
// Currently supported value is only "memberships".
|
|
|
|
// If used then response will contain empty (null) members field.
|
|
|
|
Omit string `json:"omit"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (q GroupsQuery) String() string {
|
|
|
|
return marshal(&q)
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
IndexGroups -
|
|
|
|
|
|
|
|
List the authenticated user's active groups.
|
|
|
|
|
|
|
|
The response is paginated, with a default of 10 groups per page.
|
|
|
|
|
|
|
|
Please consider using of omit=memberships parameter. Not including
|
|
|
|
member lists might significantly improve user experience of your
|
|
|
|
app for users who are participating in huge groups.
|
|
|
|
|
|
|
|
Parameters: See GroupsQuery
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) IndexGroups(ctx context.Context, req *GroupsQuery, authToken string) ([]*Group, error) {
|
2020-07-30 02:20:57 +00:00
|
|
|
httpReq, err := http.NewRequest("GET", c.endpointBase+indexGroupsEndpoint, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
URL := httpReq.URL
|
|
|
|
query := URL.Query()
|
|
|
|
if req != nil {
|
|
|
|
if req.Page != 0 {
|
|
|
|
query.Set("page", strconv.Itoa(req.Page))
|
|
|
|
}
|
|
|
|
if req.PerPage != 0 {
|
|
|
|
query.Set("per_page", strconv.Itoa(req.PerPage))
|
|
|
|
}
|
|
|
|
if req.Omit != "" {
|
|
|
|
query.Set("omit", req.Omit)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
URL.RawQuery = query.Encode()
|
|
|
|
|
|
|
|
var resp []*Group
|
2023-09-20 02:08:46 +00:00
|
|
|
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Former ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
FormerGroups -
|
|
|
|
|
|
|
|
List they groups you have left but can rejoin.
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) FormerGroups(ctx context.Context, authToken string) ([]*Group, error) {
|
2020-07-30 02:20:57 +00:00
|
|
|
httpReq, err := http.NewRequest("GET", c.endpointBase+formerGroupsEndpoint, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var resp []*Group
|
2023-09-20 02:08:46 +00:00
|
|
|
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Show ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
ShowGroup -
|
|
|
|
|
|
|
|
Loads a specific group.
|
|
|
|
|
|
|
|
Parameters:
|
2023-09-20 02:08:46 +00:00
|
|
|
|
2020-07-30 02:20:57 +00:00
|
|
|
groupID - required, ID(string)
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) ShowGroup(ctx context.Context, groupID ID, authToken string) (*Group, error) {
|
2020-07-30 02:20:57 +00:00
|
|
|
URL := fmt.Sprintf(c.endpointBase+showGroupEndpoint, groupID)
|
|
|
|
|
|
|
|
httpReq, err := http.NewRequest("GET", URL, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var resp Group
|
2023-09-20 02:08:46 +00:00
|
|
|
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &resp, nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Create ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
CreateGroup -
|
|
|
|
|
2023-09-20 02:08:46 +00:00
|
|
|
# Create a new group
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
Parameters: See GroupSettings
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings, authToken string) (*Group, error) {
|
2020-08-24 01:25:02 +00:00
|
|
|
URL := fmt.Sprintf(c.endpointBase + createGroupEndpoint)
|
|
|
|
|
|
|
|
jsonBytes, err := json.Marshal(&gs)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-24 01:25:02 +00:00
|
|
|
httpReq, err := http.NewRequest("POST", URL, bytes.NewBuffer(jsonBytes))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-07-30 02:20:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var resp Group
|
2023-09-20 02:08:46 +00:00
|
|
|
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &resp, nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Update ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
UpdateGroup -
|
|
|
|
|
2023-09-20 02:08:46 +00:00
|
|
|
# Update a group after creation
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
Parameters:
|
2023-09-20 02:08:46 +00:00
|
|
|
|
2020-07-30 02:20:57 +00:00
|
|
|
groupID - required, ID(string)
|
|
|
|
See GroupSettings
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings, authToken string) (*Group, error) {
|
2020-07-30 02:20:57 +00:00
|
|
|
URL := fmt.Sprintf(c.endpointBase+updateGroupEndpoint, groupID)
|
|
|
|
|
2020-08-24 01:25:02 +00:00
|
|
|
jsonBytes, err := json.Marshal(&gs)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-24 01:25:02 +00:00
|
|
|
httpReq, err := http.NewRequest("POST", URL, bytes.NewBuffer(jsonBytes))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-07-30 02:20:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var resp Group
|
2023-09-20 02:08:46 +00:00
|
|
|
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &resp, nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Destroy ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
DestroyGroup -
|
|
|
|
|
2023-09-20 02:08:46 +00:00
|
|
|
# Disband a group
|
2020-07-30 02:20:57 +00:00
|
|
|
|
2023-09-20 02:08:46 +00:00
|
|
|
# This action is only available to the group creator
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
Parameters:
|
2023-09-20 02:08:46 +00:00
|
|
|
|
2020-07-30 02:20:57 +00:00
|
|
|
groupID - required, ID(string)
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) DestroyGroup(ctx context.Context, groupID ID, authToken string) error {
|
2020-07-30 02:20:57 +00:00
|
|
|
url := fmt.Sprintf(c.endpointBase+destroyGroupEndpoint, groupID)
|
|
|
|
|
|
|
|
httpReq, err := http.NewRequest("POST", url, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-20 02:08:46 +00:00
|
|
|
return c.doWithAuthToken(ctx, httpReq, nil, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Join ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
JoinGroup -
|
|
|
|
|
2023-09-20 02:08:46 +00:00
|
|
|
# Join a shared group
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
Parameters:
|
2023-09-20 02:08:46 +00:00
|
|
|
|
2020-07-30 02:20:57 +00:00
|
|
|
groupID - required, ID(string)
|
|
|
|
shareToken - required, string
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) JoinGroup(ctx context.Context, groupID ID, shareToken string, authToken string) (*Group, error) {
|
2020-07-30 02:20:57 +00:00
|
|
|
URL := fmt.Sprintf(c.endpointBase+joinGroupEndpoint, groupID, shareToken)
|
|
|
|
|
|
|
|
httpReq, err := http.NewRequest("POST", URL, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var resp Group
|
2023-09-20 02:08:46 +00:00
|
|
|
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &resp, nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Rejoin ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
RejoinGroup -
|
|
|
|
|
|
|
|
Rejoin a group. Only works if you previously removed yourself.
|
|
|
|
|
|
|
|
Parameters:
|
2023-09-20 02:08:46 +00:00
|
|
|
|
2020-07-30 02:20:57 +00:00
|
|
|
groupID - required, ID(string)
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) RejoinGroup(ctx context.Context, groupID ID, authToken string) (*Group, error) {
|
2020-08-24 01:25:02 +00:00
|
|
|
URL := fmt.Sprintf(c.endpointBase + rejoinGroupEndpoint)
|
|
|
|
|
|
|
|
var data = struct {
|
|
|
|
GroupID ID `json:"group_id"`
|
|
|
|
}{
|
|
|
|
groupID,
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonBytes, err := json.Marshal(&data)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-24 01:25:02 +00:00
|
|
|
httpReq, err := http.NewRequest("POST", URL, bytes.NewBuffer(jsonBytes))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
var resp Group
|
2023-09-20 02:08:46 +00:00
|
|
|
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &resp, nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
/*/// Change Owner ///*/
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
/*
|
2021-01-22 21:47:22 +00:00
|
|
|
ChangeGroupOwner - Change owner of requested groups.
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
This action is only available to the group creator.
|
|
|
|
|
|
|
|
Response is a result object which contain status field,
|
|
|
|
the result of change owner action for the request
|
|
|
|
|
|
|
|
Parameters: See ChangeOwnerRequest
|
|
|
|
*/
|
2023-09-20 02:08:46 +00:00
|
|
|
func (c *Client) ChangeGroupOwner(ctx context.Context, reqs ChangeOwnerRequest, authToken string) (ChangeOwnerResult, error) {
|
2020-08-24 01:25:02 +00:00
|
|
|
URL := fmt.Sprintf(c.endpointBase + changeGroupOwnerEndpoint)
|
|
|
|
|
|
|
|
var data = struct {
|
|
|
|
Requests []ChangeOwnerRequest `json:"requests"`
|
|
|
|
}{
|
|
|
|
[]ChangeOwnerRequest{reqs},
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonBytes, err := json.Marshal(&data)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return ChangeOwnerResult{}, err
|
|
|
|
}
|
|
|
|
|
2020-08-24 01:25:02 +00:00
|
|
|
httpReq, err := http.NewRequest("POST", URL, bytes.NewBuffer(jsonBytes))
|
|
|
|
if err != nil {
|
|
|
|
return ChangeOwnerResult{}, err
|
|
|
|
}
|
2020-07-30 02:20:57 +00:00
|
|
|
|
|
|
|
var resp struct {
|
|
|
|
Results []ChangeOwnerResult `json:"results"`
|
|
|
|
}
|
|
|
|
|
2023-09-20 02:08:46 +00:00
|
|
|
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
|
2020-07-30 02:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return ChangeOwnerResult{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp.Results) < 1 {
|
|
|
|
return ChangeOwnerResult{}, errors.New("failed to parse results")
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp.Results[0], nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
type changeOwnerStatusCode string
|
2020-07-30 02:20:57 +00:00
|
|
|
|
2021-01-22 21:47:22 +00:00
|
|
|
// Change owner Status Codes
|
2020-07-30 02:20:57 +00:00
|
|
|
const (
|
2021-01-22 21:47:22 +00:00
|
|
|
ChangeOwnerOk changeOwnerStatusCode = "200"
|
|
|
|
ChangeOwnerRequesterNewOwner changeOwnerStatusCode = "400"
|
|
|
|
ChangeOwnerNotOwner changeOwnerStatusCode = "403"
|
|
|
|
ChangeOwnerBadGroupOrOwner changeOwnerStatusCode = "404"
|
|
|
|
ChangeOwnerBadRequest changeOwnerStatusCode = "405"
|
2020-07-30 02:20:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// String returns the description of the status code according to GroupMe
|
2021-01-22 21:47:22 +00:00
|
|
|
func (c changeOwnerStatusCode) String() string {
|
|
|
|
return map[changeOwnerStatusCode]string{
|
|
|
|
ChangeOwnerOk: "success",
|
|
|
|
ChangeOwnerRequesterNewOwner: "requester is also a new owner",
|
|
|
|
ChangeOwnerNotOwner: "requester is not the owner of the group",
|
|
|
|
ChangeOwnerBadGroupOrOwner: "group or new owner not found or new owner is not member of the group",
|
|
|
|
ChangeOwnerBadRequest: "request object is missing required field or any of the required fields is not an ID",
|
2020-07-30 02:20:57 +00:00
|
|
|
}[c]
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChangeOwnerRequest defines the new owner of a group
|
|
|
|
type ChangeOwnerRequest struct {
|
|
|
|
// Required
|
|
|
|
GroupID string `json:"group_id"`
|
|
|
|
// Required. UserId of the new owner of the group
|
|
|
|
// who must be an active member of the group
|
|
|
|
OwnerID string `json:"owner_id"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r ChangeOwnerRequest) String() string {
|
|
|
|
return marshal(&r)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChangeOwnerResult holds the status of the group owner change
|
|
|
|
type ChangeOwnerResult struct {
|
|
|
|
GroupID string `json:"group_id"`
|
|
|
|
// UserId of the new owner of the group who is
|
|
|
|
// an active member of the group
|
|
|
|
OwnerID string `json:"owner_id"`
|
2021-01-22 21:47:22 +00:00
|
|
|
Status changeOwnerStatusCode `json:"status"`
|
2020-07-30 02:20:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r ChangeOwnerResult) String() string {
|
|
|
|
return marshal(&r)
|
|
|
|
}
|