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  }