Skip to content

Commit ae48fd7

Browse files
committed
Add group endpoint support
1 parent 4344058 commit ae48fd7

File tree

7 files changed

+622
-0
lines changed

7 files changed

+622
-0
lines changed

group/group.go

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
package group
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
"net/url"
8+
"strconv"
9+
"strings"
10+
"time"
11+
12+
"github.com/messagebird/go-rest-api/contact"
13+
14+
messagebird "github.com/messagebird/go-rest-api"
15+
)
16+
17+
// Group gets returned by the API.
18+
type Group struct {
19+
ID string
20+
HRef string
21+
Name string
22+
Contacts struct {
23+
TotalCount int
24+
HRef string
25+
}
26+
CreatedDatetime time.Time
27+
UpdatedDatetime time.Time
28+
}
29+
30+
type GroupList struct {
31+
Offset int
32+
Limit int
33+
Count int
34+
TotalCount int
35+
Links struct {
36+
First string
37+
Previous string
38+
Next string
39+
Last string
40+
}
41+
Items []Group
42+
}
43+
44+
// ListOptions can be used to set pagination options in List() and ListContacts().
45+
type ListOptions struct {
46+
Limit, Offset int
47+
}
48+
49+
// Request represents a contact for write operations, e.g. for creating a new
50+
// group or updating an existing one.
51+
type Request struct {
52+
Name string `json:"name"`
53+
}
54+
55+
const (
56+
// path represents the path to the Groups resource.
57+
path = "groups"
58+
59+
// contactPath represents the path to the Contacts resource within Groups.
60+
contactPath = "contacts"
61+
)
62+
63+
// DefaultListOptions provides reasonable values for List().
64+
var DefaultListOptions = &ListOptions{
65+
Limit: 10,
66+
Offset: 0,
67+
}
68+
69+
func Create(c *messagebird.Client, request *Request) (*Group, error) {
70+
if err := validateCreate(request); err != nil {
71+
return nil, err
72+
}
73+
74+
group := &Group{}
75+
76+
err := c.Request(group, http.MethodPost, path, request)
77+
if err != nil {
78+
return nil, err
79+
}
80+
81+
return group, nil
82+
}
83+
84+
func validateCreate(request *Request) error {
85+
if request.Name == "" {
86+
return errors.New("name is required")
87+
}
88+
89+
return nil
90+
}
91+
92+
// Delete attempts deleting the group with the provided ID. If nil is returned,
93+
// the resource was deleted successfully.
94+
func Delete(c *messagebird.Client, id string) error {
95+
return c.Request(nil, http.MethodDelete, path+"/"+id, nil)
96+
}
97+
98+
// List retrieves a paginated list of groups, based on the options provided.
99+
// It's worth noting DefaultListOptions.
100+
func List(c *messagebird.Client, options *ListOptions) (*GroupList, error) {
101+
query, err := listQuery(options)
102+
if err != nil {
103+
return nil, err
104+
}
105+
106+
groupList := &GroupList{}
107+
108+
if err := c.Request(groupList, http.MethodGet, path+"?"+query, nil); err != nil {
109+
return nil, err
110+
}
111+
112+
return groupList, nil
113+
}
114+
115+
func listQuery(options *ListOptions) (string, error) {
116+
if options.Limit < 10 {
117+
return "", fmt.Errorf("minimum limit is 10, got %d", options.Limit)
118+
}
119+
120+
if options.Offset < 0 {
121+
return "", fmt.Errorf("offset can not be negative")
122+
}
123+
124+
values := &url.Values{}
125+
126+
values.Set("limit", strconv.Itoa(options.Limit))
127+
values.Set("offset", strconv.Itoa(options.Offset))
128+
129+
return values.Encode(), nil
130+
}
131+
132+
// Read retrieves the information of an existing group.
133+
func Read(c *messagebird.Client, id string) (*Group, error) {
134+
group := &Group{}
135+
136+
err := c.Request(group, http.MethodGet, path+"/"+id, nil)
137+
if err != nil {
138+
return nil, err
139+
}
140+
141+
return group, nil
142+
}
143+
144+
// Update overrides the group with any values provided in request.
145+
func Update(c *messagebird.Client, id string, groupRequest *Request) error {
146+
if err := validateUpdate(groupRequest); err != nil {
147+
return err
148+
}
149+
150+
return c.Request(nil, http.MethodPatch, path+"/"+id, groupRequest)
151+
}
152+
153+
func validateUpdate(groupRequest *Request) error {
154+
if groupRequest.Name == "" {
155+
return errors.New("name is required")
156+
}
157+
158+
return nil
159+
}
160+
161+
// AddContacts adds a maximum of 50 contacts to the group.
162+
func AddContacts(c *messagebird.Client, groupID string, contactIDS []string) error {
163+
if err := validateAddContacts(contactIDS); err != nil {
164+
return err
165+
}
166+
167+
query := addContactsQuery(contactIDS)
168+
169+
formattedPath := fmt.Sprintf("%s/%s/%s?%s", path, groupID, contactPath, query)
170+
171+
return c.Request(nil, http.MethodGet, formattedPath, nil)
172+
}
173+
174+
func validateAddContacts(contactIDS []string) error {
175+
count := len(contactIDS)
176+
177+
// len(nil) == 0: https://golang.org/ref/spec#Length_and_capacity
178+
if count == 0 {
179+
return fmt.Errorf("contactIDS is required")
180+
}
181+
182+
if count > 50 {
183+
return fmt.Errorf("can not add more than 50 contacts per request, got %d", count)
184+
}
185+
186+
return nil
187+
}
188+
189+
// addContactsQuery gets a query string to add contacts to a group. We're using
190+
// the alternative "/foo?_method=PUT&key=value" alternative to send the contact
191+
// IDs as GET params. Sending these in the request body would require a painful
192+
// workaround, as client.Request sends request bodies as JSON by default. See
193+
// also: https://developers.messagebird.com/docs/alternatives.
194+
func addContactsQuery(contactIDS []string) string {
195+
// Slice's length is one bigger than len(IDs) for the _method param.
196+
params := make([]string, 0, len(contactIDS)+1)
197+
198+
params = append(params, "_method="+http.MethodPut)
199+
200+
for _, contactID := range contactIDS {
201+
params = append(params, "ids[]="+contactID)
202+
}
203+
204+
return strings.Join(params, "&")
205+
}
206+
207+
// ListContacts lists the contacts that are a member of a group.
208+
func ListContacts(c *messagebird.Client, groupID string, options *ListOptions) (*contact.ContactList, error) {
209+
query, err := listQuery(options)
210+
if err != nil {
211+
return nil, err
212+
}
213+
214+
formattedPath := fmt.Sprintf("%s/%s/%s?%s", path, groupID, contactPath, query)
215+
216+
contacts := &contact.ContactList{}
217+
218+
err = c.Request(contacts, http.MethodGet, formattedPath, nil)
219+
220+
if err != nil {
221+
return nil, err
222+
}
223+
224+
return contacts, nil
225+
}
226+
227+
// RemoveContact removes the contact from a group. If nil is returned, the
228+
// operation was successful.
229+
func RemoveContact(c *messagebird.Client, groupID, contactID string) error {
230+
formattedPath := fmt.Sprintf("%s/%s/contacts/%s", path, groupID, contactID)
231+
232+
return c.Request(nil, http.MethodDelete, formattedPath, nil)
233+
}

0 commit comments

Comments
 (0)