Skip to content

Commit

Permalink
Merge pull request #15 from savannahghi/add-api-to-activate-subscript…
Browse files Browse the repository at this point in the history
…ions-to-offers

feat: add api to activate subscriptions to offers
  • Loading branch information
Salaton committed Jun 15, 2023
2 parents d399b2f + 7c8a904 commit 9c4d5b5
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 5 deletions.
15 changes: 15 additions & 0 deletions models.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,18 @@ type PremiumSMSResponse struct {
Direction string `json:"direction"`
State string `json:"state"`
}

// Subscription represents the response that is returned when activating a subscription to an offer
type Subscription struct {
GUID string `json:"guid"`
Gateway string `json:"gateway"`
Offer string `json:"offer"`
Msisdn string `json:"msisdn"`
LinkID string `json:"link_id"`
ActivationDate string `json:"activation_date"`
DeactivationDate any `json:"deactivation_date"`
DeactivationType string `json:"deactivation_type"`
Sms []any `json:"sms"`
Created string `json:"created"`
Updated string `json:"updated"`
}
71 changes: 66 additions & 5 deletions sms.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ func (l CommsLib) SendBulkSMS(ctx context.Context, message string, recipients []
return &bulkSMS, nil
}

// SendPremiumSMS is used to send a premium SMS using SILCOMMS gateway
// message - message to be sent via the premium SMS
// msisdn - phone number to receive the premium SMS
// subscription - subscription/offer associated with the premium SMS
// SendPremiumSMS is used to send a premium SMS using SILCOMMS gateway.
// message - message to be sent via the premium SMS.
// msisdn - phone number to receive the premium SMS.
// subscription - subscription/offer associated with the premium SMS.
func (l CommsLib) SendPremiumSMS(ctx context.Context, message, msisdn, subscription string) (*PremiumSMSResponse, error) {
path := "/v1/sms/sms/"
payload := struct {
Expand All @@ -106,8 +106,9 @@ func (l CommsLib) SendPremiumSMS(ctx context.Context, message, msisdn, subscript

response, err := l.client.MakeRequest(ctx, http.MethodPost, path, nil, payload, true)
if err != nil {
return nil, fmt.Errorf("failed to make send premium sms request: %v", err)
return nil, fmt.Errorf("failed to make send premium sms request: %w", err)
}

if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("invalid send premium sms response code, got: %d", response.StatusCode)
}
Expand All @@ -126,3 +127,63 @@ func (l CommsLib) SendPremiumSMS(ctx context.Context, message, msisdn, subscript

return &premiumSMS, nil
}

// ActivateSubscription is used activate a subscription to an offer on SILCOMMS.
// msisdn - phone number to be to activate a subscription to an offer.
// offer - offercode used to create a subscription.
func (l CommsLib) ActivateSubscription(ctx context.Context, offer string, msisdn string) (bool, error) {
path := "/v1/sms/subscriptions/"
payload := struct {
Offer string `json:"offer"`
Msisdn string `json:"msisdn"`
}{
Offer: offer,
Msisdn: msisdn,
}

response, err := l.client.MakeRequest(ctx, http.MethodPost, path, nil, payload, true)
if err != nil {
return false, fmt.Errorf("failed to make activate subscription request: %w", err)
}

if response.StatusCode != http.StatusOK {
return false, fmt.Errorf("invalid activate subscription response code, got: %d", response.StatusCode)
}

return true, nil
}

// GetSubscriptions fetches subscriptions from SILCOMMs based on provided query params
// params - query params used to get a subscription to an offer.
func (l CommsLib) GetSubscriptions(ctx context.Context, queryParams map[string]string) ([]*Subscription, error) {
path := "/v1/sms/subscriptions/"

response, err := l.client.MakeRequest(ctx, http.MethodGet, path, queryParams, nil, true)
if err != nil {
return nil, fmt.Errorf("failed to make get subscriptions request: %w", err)
}

if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("invalid get subscriptions response code, got: %d", response.StatusCode)
}

var resp APIResponse
err = json.NewDecoder(response.Body).Decode(&resp)
if err != nil {
return nil, fmt.Errorf("failed to decode get subscriptions api response: %w", err)
}

var resultResponse ResultsResponse
err = mapstructure.Decode(resp.Data, &resultResponse)
if err != nil {
return nil, fmt.Errorf("failed to decode result response data in api response: %w", err)
}

var subscriptions []*Subscription
err = mapstructure.Decode(resultResponse.Results, &subscriptions)
if err != nil {
return nil, fmt.Errorf("failed to decode subscriptions data in api response: %w", err)
}

return subscriptions, nil
}
164 changes: 164 additions & 0 deletions sms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,167 @@ func TestSILCommsLib_SendPremiumSMS(t *testing.T) {
})
}
}

func TestSILCommsLib_ActivateSubscription(t *testing.T) {
ctx := context.Background()
type args struct {
ctx context.Context
offer string
msisdn string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "Happy case: activate subscription",
args: args{
ctx: ctx,
offer: "01262626626",
msisdn: gofakeit.Phone(),
},
wantErr: false,
},
{
name: "Sad case: invalid status code",
args: args{
ctx: ctx,
offer: "01262626626",
msisdn: gofakeit.Phone(),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
silcomms.MockLogin()

l := silcomms.MustNewSILCommsLib()

if tt.name == "Happy case: activate subscription" {
httpmock.RegisterResponder(http.MethodPost, fmt.Sprintf("%s/v1/sms/subscriptions/", silcomms.BaseURL), func(r *http.Request) (*http.Response, error) {
resp := silcomms.APIResponse{
Status: silcomms.StatusSuccess,
Message: "success",
Data: map[string]interface{}{
"guid": "123456",
"offer": "123456",
"msisdn": "123456",
},
}
return httpmock.NewJsonResponse(http.StatusOK, resp)
})
}

if tt.name == "Sad case: invalid status code" {
httpmock.RegisterResponder(http.MethodPost, fmt.Sprintf("%s/v1/sms/subscriptions/", silcomms.BaseURL), func(r *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(http.StatusUnauthorized, nil)
})
}

got, err := l.ActivateSubscription(tt.args.ctx, tt.args.offer, tt.args.msisdn)
if (err != nil) != tt.wantErr {
t.Errorf("SILCommsLib.ActivateSubscription() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && got == false {
t.Errorf("SILCommsLib.ActivateSubscription() expected response not to be false for %v", tt.name)
return
}
})
}
}

func TestSILCommsLib_GetSubscriptions(t *testing.T) {
ctx := context.Background()
type args struct {
ctx context.Context
queryParams map[string]string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "Happy case: get subscription",
args: args{
ctx: ctx,
queryParams: map[string]string{
"msisdn": gofakeit.Phone(),
"offer": "01262626626",
},
},
wantErr: false,
},
{
name: "Sad case: invalid status code",
args: args{
ctx: ctx,
queryParams: map[string]string{
"msisdn": gofakeit.Phone(),
"offer": "01262626626",
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
silcomms.MockLogin()

l := silcomms.MustNewSILCommsLib()

if tt.name == "Happy case: get subscription" {
httpmock.RegisterResponder(http.MethodGet, fmt.Sprintf("%s/v1/sms/subscriptions/", silcomms.BaseURL), func(r *http.Request) (*http.Response, error) {
resp := silcomms.APIResponse{
Status: silcomms.StatusSuccess,
Message: "success",
Data: map[string]interface{}{
"count": 1,
"next": nil,
"previous": nil,
"results": []map[string]interface{}{
{
"guid": "e602b8b8-9591-4526-915d-57ef2579d8c4",
"gateway": "SAFARICOM",
"offer": "0022345234",
"msisdn": "+254722345678",
"link_id": "123123123123123",
"activation_date": "2022-08-04 14:11:17.206377+03:00",
"deactivation_date": nil,
"deactivation_type": "USER_INITIATED",
"sms": []string{},
"created": "2022-08-04 14:11:17.206377+03:00",
"updated": "2022-08-04 14:11:17.206377+03:00",
},
},
},
}
return httpmock.NewJsonResponse(http.StatusOK, resp)
})
}

if tt.name == "Sad case: invalid status code" {
httpmock.RegisterResponder(http.MethodGet, fmt.Sprintf("%s/v1/sms/subscriptions/", silcomms.BaseURL), func(r *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(http.StatusUnauthorized, nil)
})
}

got, err := l.GetSubscriptions(tt.args.ctx, tt.args.queryParams)
if (err != nil) != tt.wantErr {
t.Errorf("SILCommsLib.GetSubscriptions() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && got == nil {
t.Errorf("SILCommsLib.GetSubscriptions() expected response not to be nil for %v", tt.name)
return
}
})
}
}

0 comments on commit 9c4d5b5

Please sign in to comment.