github.com/mailgun/mailgun-go/v3@v3.6.4/members.go (about) 1 package mailgun 2 3 import ( 4 "context" 5 "encoding/json" 6 "strconv" 7 ) 8 9 // yes and no are variables which provide us the ability to take their addresses. 10 // Subscribed and Unsubscribed are pointers to these booleans. 11 // 12 // We use a pointer to boolean as a kind of trinary data type: 13 // if nil, the relevant data type remains unspecified. 14 // Otherwise, its value is either true or false. 15 var ( 16 yes bool = true 17 no bool = false 18 ) 19 20 // Mailing list members have an attribute that determines if they've subscribed to the mailing list or not. 21 // This attribute may be used to filter the results returned by GetSubscribers(). 22 // All, Subscribed, and Unsubscribed provides a convenient and readable syntax for specifying the scope of the search. 23 var ( 24 All *bool = nil 25 Subscribed *bool = &yes 26 Unsubscribed *bool = &no 27 ) 28 29 // A Member structure represents a member of the mailing list. 30 // The Vars field can represent any JSON-encodable data. 31 type Member struct { 32 Address string `json:"address,omitempty"` 33 Name string `json:"name,omitempty"` 34 Subscribed *bool `json:"subscribed,omitempty"` 35 Vars map[string]interface{} `json:"vars,omitempty"` 36 } 37 38 type memberListResponse struct { 39 Lists []Member `json:"items"` 40 Paging Paging `json:"paging"` 41 } 42 43 type memberResponse struct { 44 Member Member `json:"member"` 45 } 46 47 type MemberListIterator struct { 48 memberListResponse 49 mg Mailgun 50 err error 51 } 52 53 // Used by List methods to specify what list parameters to send to the mailgun API 54 type ListOptions struct { 55 Limit int 56 } 57 58 func (mg *MailgunImpl) ListMembers(address string, opts *ListOptions) *MemberListIterator { 59 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, address) + "/pages") 60 r.setClient(mg.Client()) 61 r.setBasicAuth(basicAuthUser, mg.APIKey()) 62 if opts != nil { 63 if opts.Limit != 0 { 64 r.addParameter("limit", strconv.Itoa(opts.Limit)) 65 } 66 } 67 url, err := r.generateUrlWithParameters() 68 return &MemberListIterator{ 69 mg: mg, 70 memberListResponse: memberListResponse{Paging: Paging{Next: url, First: url}}, 71 err: err, 72 } 73 } 74 75 // If an error occurred during iteration `Err()` will return non nil 76 func (li *MemberListIterator) Err() error { 77 return li.err 78 } 79 80 // Next retrieves the next page of items from the api. Returns false when there 81 // no more pages to retrieve or if there was an error. Use `.Err()` to retrieve 82 // the error 83 func (li *MemberListIterator) Next(ctx context.Context, items *[]Member) bool { 84 if li.err != nil { 85 return false 86 } 87 li.err = li.fetch(ctx, li.Paging.Next) 88 if li.err != nil { 89 return false 90 } 91 *items = li.Lists 92 if len(li.Lists) == 0 { 93 return false 94 } 95 return true 96 } 97 98 // First retrieves the first page of items from the api. Returns false if there 99 // was an error. It also sets the iterator object to the first page. 100 // Use `.Err()` to retrieve the error. 101 func (li *MemberListIterator) First(ctx context.Context, items *[]Member) bool { 102 if li.err != nil { 103 return false 104 } 105 li.err = li.fetch(ctx, li.Paging.First) 106 if li.err != nil { 107 return false 108 } 109 *items = li.Lists 110 return true 111 } 112 113 // Last retrieves the last page of items from the api. 114 // Calling Last() is invalid unless you first call First() or Next() 115 // Returns false if there was an error. It also sets the iterator object 116 // to the last page. Use `.Err()` to retrieve the error. 117 func (li *MemberListIterator) Last(ctx context.Context, items *[]Member) bool { 118 if li.err != nil { 119 return false 120 } 121 li.err = li.fetch(ctx, li.Paging.Last) 122 if li.err != nil { 123 return false 124 } 125 *items = li.Lists 126 return true 127 } 128 129 // Previous retrieves the previous page of items from the api. Returns false when there 130 // no more pages to retrieve or if there was an error. Use `.Err()` to retrieve 131 // the error if any 132 func (li *MemberListIterator) Previous(ctx context.Context, items *[]Member) bool { 133 if li.err != nil { 134 return false 135 } 136 if li.Paging.Previous == "" { 137 return false 138 } 139 li.err = li.fetch(ctx, li.Paging.Previous) 140 if li.err != nil { 141 return false 142 } 143 *items = li.Lists 144 if len(li.Lists) == 0 { 145 return false 146 } 147 return true 148 } 149 150 func (li *MemberListIterator) fetch(ctx context.Context, url string) error { 151 r := newHTTPRequest(url) 152 r.setClient(li.mg.Client()) 153 r.setBasicAuth(basicAuthUser, li.mg.APIKey()) 154 155 return getResponseFromJSON(ctx, r, &li.memberListResponse) 156 } 157 158 // GetMember returns a complete Member structure for a member of a mailing list, 159 // given only their subscription e-mail address. 160 func (mg *MailgunImpl) GetMember(ctx context.Context, s, l string) (Member, error) { 161 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, l) + "/" + s) 162 r.setClient(mg.Client()) 163 r.setBasicAuth(basicAuthUser, mg.APIKey()) 164 response, err := makeGetRequest(ctx, r) 165 if err != nil { 166 return Member{}, err 167 } 168 var resp memberResponse 169 err = response.parseFromJSON(&resp) 170 return resp.Member, err 171 } 172 173 // CreateMember registers a new member of the indicated mailing list. 174 // If merge is set to true, then the registration may update an existing Member's settings. 175 // Otherwise, an error will occur if you attempt to add a member with a duplicate e-mail address. 176 func (mg *MailgunImpl) CreateMember(ctx context.Context, merge bool, addr string, prototype Member) error { 177 vs, err := json.Marshal(prototype.Vars) 178 if err != nil { 179 return err 180 } 181 182 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr)) 183 r.setClient(mg.Client()) 184 r.setBasicAuth(basicAuthUser, mg.APIKey()) 185 p := newFormDataPayload() 186 p.addValue("upsert", yesNo(merge)) 187 p.addValue("address", prototype.Address) 188 p.addValue("name", prototype.Name) 189 p.addValue("vars", string(vs)) 190 if prototype.Subscribed != nil { 191 p.addValue("subscribed", yesNo(*prototype.Subscribed)) 192 } 193 _, err = makePostRequest(ctx, r, p) 194 return err 195 } 196 197 // UpdateMember lets you change certain details about the indicated mailing list member. 198 // Address, Name, Vars, and Subscribed fields may be changed. 199 func (mg *MailgunImpl) UpdateMember(ctx context.Context, s, l string, prototype Member) (Member, error) { 200 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, l) + "/" + s) 201 r.setClient(mg.Client()) 202 r.setBasicAuth(basicAuthUser, mg.APIKey()) 203 p := newFormDataPayload() 204 if prototype.Address != "" { 205 p.addValue("address", prototype.Address) 206 } 207 if prototype.Name != "" { 208 p.addValue("name", prototype.Name) 209 } 210 if prototype.Vars != nil { 211 vs, err := json.Marshal(prototype.Vars) 212 if err != nil { 213 return Member{}, err 214 } 215 p.addValue("vars", string(vs)) 216 } 217 if prototype.Subscribed != nil { 218 p.addValue("subscribed", yesNo(*prototype.Subscribed)) 219 } 220 response, err := makePutRequest(ctx, r, p) 221 if err != nil { 222 return Member{}, err 223 } 224 var envelope struct { 225 Member Member `json:"member"` 226 } 227 err = response.parseFromJSON(&envelope) 228 return envelope.Member, err 229 } 230 231 // DeleteMember removes the member from the list. 232 func (mg *MailgunImpl) DeleteMember(ctx context.Context, member, addr string) error { 233 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr) + "/" + member) 234 r.setClient(mg.Client()) 235 r.setBasicAuth(basicAuthUser, mg.APIKey()) 236 _, err := makeDeleteRequest(ctx, r) 237 return err 238 } 239 240 // CreateMemberList registers multiple Members and non-Member members to a single mailing list 241 // in a single round-trip. 242 // u indicates if the existing members should be updated or duplicates should be updated. 243 // Use All to elect not to provide a default. 244 // The newMembers list can take one of two JSON-encodable forms: an slice of strings, or 245 // a slice of Member structures. 246 // If a simple slice of strings is passed, each string refers to the member's e-mail address. 247 // Otherwise, each Member needs to have at least the Address field filled out. 248 // Other fields are optional, but may be set according to your needs. 249 func (mg *MailgunImpl) CreateMemberList(ctx context.Context, u *bool, addr string, newMembers []interface{}) error { 250 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr) + ".json") 251 r.setClient(mg.Client()) 252 r.setBasicAuth(basicAuthUser, mg.APIKey()) 253 p := newFormDataPayload() 254 if u != nil { 255 p.addValue("upsert", yesNo(*u)) 256 } 257 bs, err := json.Marshal(newMembers) 258 if err != nil { 259 return err 260 } 261 p.addValue("members", string(bs)) 262 _, err = makePostRequest(ctx, r, p) 263 return err 264 }