Skip to content

Commit

Permalink
Merge 05be951 into 9f1c369
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Jones committed Mar 1, 2016
2 parents 9f1c369 + 05be951 commit 8cb8a80
Show file tree
Hide file tree
Showing 2 changed files with 373 additions and 0 deletions.
230 changes: 230 additions & 0 deletions payload/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
// Package payload is a helper package which contains a payload
// builder to make constructing notification payloads easier.
package payload

import "encoding/json"

type payload struct {
content map[string]interface{}
}

type aps struct {
Alert interface{} `json:"alert,omitempty"`
Badge interface{} `json:"badge,omitempty"`
Category string `json:"category,omitempty"`
ContentAvailable int `json:"content-available,omitempty"`
URLArgs []string `json:"url-args,omitempty"`
Sound string `json:"sound,omitempty"`
}

type alert struct {
Action string `json:"action,omitempty"`
ActionLocKey string `json:"action-loc-key,omitempty"`
Body string `json:"body,omitempty"`
LaunchImage string `json:"launch-image,omitempty"`
LocArgs []string `json:"loc-args,omitempty"`
LocKey string `json:"loc-key,omitempty"`
Title string `json:"title,omitempty"`
TitleLocArgs []string `json:"title-loc-args,omitempty"`
TitleLocKey string `json:"title-loc-key,omitempty"`
}

// NewPayload represents a notification payload.
func NewPayload() *payload {
return &payload{
map[string]interface{}{
"aps": &aps{},
},
}
}

// Sets the aps alert on the payload.
// This will display a notification alert message to the user.
// {"aps":{"alert":alert}}
func (p *payload) Alert(alert interface{}) *payload {
p.aps().Alert = alert
return p
}

// Sets the aps badge on the payload.
// This will display a numeric badge on the app icon.
// {"aps":{"badge":b}}
func (p *payload) Badge(b int) *payload {
p.aps().Badge = b
return p
}

// Sets the aps badge on the payload to 0.
// This will clear the badge on the app icon.
// {"aps":{"badge":0}}
func (p *payload) ZeroBadge() *payload {
p.aps().Badge = 0
return p
}

// Removes the badge attribute from the payload.
// This will leave the badge on the app icon unchanged.
// If you wish to clear the app icon badge, use ZeroBadge() instead.
// {"aps":{}}
func (p *payload) UnsetBadge() *payload {
p.aps().Badge = nil
return p
}

// Sets the aps sound on the payload.
// This will play a sound from the app bundle, or the default sound otherwise.
// {"aps":{"sound":sound}}
func (p *payload) Sound(sound string) *payload {
p.aps().Sound = sound
return p
}

// Sets the aps content-available on the payload to 1.
// This will indicate to the app that there is new content available to download
// and launch the app in the background.
// {"aps":{"content-available":1}}
func (p *payload) ContentAvailable() *payload {
p.aps().ContentAvailable = 1
return p
}

// Sets the aps content-available on the payload to 1.
// This is an alias for ContentAvailable().
// {"aps":{"content-available":1}}
func (p *payload) NewsstandAvailable() *payload {
return p.ContentAvailable()
}

// Custom payload

// Sets a custom key and value on the payload.
// This will add custom key/value data to the notification payload at root level.
// {"aps":{}, key:value}
func (p *payload) Custom(key string, val interface{}) *payload {
p.content[key] = val
return p
}

// Alert dictionary

// Sets the aps alert title on the payload.
// This will display a short string describing the purpose of the notification.
// Apple Watch & Safari display this string as part of the notification interface.
// {"aps":{"alert":"title"}}
func (p *payload) AlertTitle(title string) *payload {
p.aps().alert().Title = title
return p
}

// Sets the aps alert title localization key on the payload.
// This is the key to a title string in the Localizable.strings file for the
// current localization. See Localized Formatted Strings in Apple documentation
// for more information.
// {"aps":{"alert":{"title-loc-key":key}}}
func (p *payload) AlertTitleLocKey(key string) *payload {
p.aps().alert().TitleLocKey = key
return p
}

// Sets the aps alert title localization args on the payload.
// These are the variable string values to appear in place of the format
// specifiers in title-loc-key. See Localized Formatted Strings in Apple
// documentation for more information.
// {"aps":{"alert":{"title-loc-args":args}}}
func (p *payload) AlertTitleLocArgs(args []string) *payload {
p.aps().alert().TitleLocArgs = args
return p
}

// Sets the aps alert body on the payload.
// This is the text of the alert message.
// {"aps":{"alert":{"body":body}}}
func (p *payload) AlertBody(body string) *payload {
p.aps().alert().Body = body
return p
}

// Sets the aps launch image on the payload.
// This is the filename of an image file in the app bundle. The image is used
// as the launch image when users tap the action button or move the action
// slider.
// {"aps":{"alert":{"launch-image":image}}}
func (p *payload) AlertLaunchImage(image string) *payload {
p.aps().alert().LaunchImage = image
return p
}

// Sets the aps alert localization key on the payload.
// This is the key to an alert-message string in the Localizable.strings file
// for the current localization. See Localized Formatted Strings in Apple
// documentation for more information.
// {"aps":{"alert":{"loc-key":key}}}
func (p *payload) AlertLocKey(key string) *payload {
p.aps().alert().LocKey = key
return p
}

// Sets the aps alert action on the payload.
// This is the label of the action button, if the user sets the notifications
// to appear as alerts. This label should be succinct, such as “Details” or
// “Read more”. If omitted, the default value is “Show”.
// {"aps":{"alert":{"action":action}}}
func (p *payload) AlertAction(action string) *payload {
p.aps().alert().Action = action
return p
}

// Sets the aps alert action localization key on the payload.
// This is the the string used as a key to get a localized string in the current
// localization to use for the notfication right button’s title instead of
// “View”. See Localized Formatted Strings in Apple documentation for more
// information.
// {"aps":{"alert":{"action-loc-key":key}}}
func (p *payload) AlertActionLocKey(key string) *payload {
p.aps().alert().ActionLocKey = key
return p
}

// General

// Sets the aps category on the payload.
// This is a string value that represents the identifier property of the
// UIMutableUserNotificationCategory object you created to define custom actions.
// {"aps":{"alert":{"category":category}}}
func (p *payload) Category(category string) *payload {
p.aps().Category = category
return p
}

// Sets the mdm on the payload.
// This is for Apple Mobile Device Management (mdm) payloads.
// {"aps":{}:"mdm":mdm}
func (p *payload) Mdm(mdm string) *payload {
p.content["mdm"] = mdm
return p
}

// Sets the aps category on the payload.
// This specifies an array of values that are paired with the placeholders
// inside the urlFormatString value of your website.json file.
// See Apple Notification Programming Guide for Websites.
// {"aps":{"url-args":urlArgs}}
func (p *payload) URLArgs(urlArgs []string) *payload {
p.aps().URLArgs = urlArgs
return p
}

func (p *payload) MarshalJSON() ([]byte, error) {
return json.Marshal(p.content)
}

func (p *payload) aps() *aps {
return p.content["aps"].(*aps)
}

func (a *aps) alert() *alert {
if _, ok := a.Alert.(*alert); !ok {
a.Alert = &alert{}
}
return a.Alert.(*alert)
}
143 changes: 143 additions & 0 deletions payload/builder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package payload_test

import (
"encoding/json"
"testing"

. "github.com/sideshow/apns2/payload"
"github.com/stretchr/testify/assert"
)

func TestEmptyPayload(t *testing.T) {
payload := NewPayload()
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{}}`, string(b))
}

func TestAlert(t *testing.T) {
payload := NewPayload().Alert("hello")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":"hello"}}`, string(b))
}

func TestBadge(t *testing.T) {
payload := NewPayload().Badge(1)
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"badge":1}}`, string(b))
}

func TestZeroBadge(t *testing.T) {
payload := NewPayload().ZeroBadge()
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"badge":0}}`, string(b))
}

func TestUnsetBadge(t *testing.T) {
payload := NewPayload().Badge(1).UnsetBadge()
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{}}`, string(b))
}

func TestSound(t *testing.T) {
payload := NewPayload().Sound("Default.caf")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"sound":"Default.caf"}}`, string(b))
}

func TestContentAvailable(t *testing.T) {
payload := NewPayload().ContentAvailable()
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"content-available":1}}`, string(b))
}

func TestNewsstandAvailable(t *testing.T) {
payload := NewPayload().NewsstandAvailable()
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"content-available":1}}`, string(b))
}

func TestCustom(t *testing.T) {
payload := NewPayload().Custom("key", "val")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{},"key":"val"}`, string(b))
}

func TestCustomMap(t *testing.T) {
payload := NewPayload().Custom("key", map[string]interface{}{
"map": 1,
})
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{},"key":{"map":1}}`, string(b))
}

func TestAlertTitle(t *testing.T) {
payload := NewPayload().AlertTitle("hello")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":{"title":"hello"}}}`, string(b))
}

func TestAlertTitleLocKey(t *testing.T) {
payload := NewPayload().AlertTitleLocKey("GAME_PLAY_REQUEST_FORMAT")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":{"title-loc-key":"GAME_PLAY_REQUEST_FORMAT"}}}`, string(b))
}

func TestAlertTitleLocArgs(t *testing.T) {
payload := NewPayload().AlertTitleLocArgs([]string{"Jenna", "Frank"})
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":{"title-loc-args":["Jenna","Frank"]}}}`, string(b))
}

func TestAlertBody(t *testing.T) {
payload := NewPayload().AlertBody("body")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":{"body":"body"}}}`, string(b))
}

func TestAlertLaunchImage(t *testing.T) {
payload := NewPayload().AlertLaunchImage("Default.png")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":{"launch-image":"Default.png"}}}`, string(b))
}

func TestAlertLocKey(t *testing.T) {
payload := NewPayload().AlertLocKey("LOC")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":{"loc-key":"LOC"}}}`, string(b))
}

func TestAlertAction(t *testing.T) {
payload := NewPayload().AlertAction("action")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":{"action":"action"}}}`, string(b))
}

func TestAlertActionLocKey(t *testing.T) {
payload := NewPayload().AlertActionLocKey("PLAY")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":{"action-loc-key":"PLAY"}}}`, string(b))
}

func TestCategory(t *testing.T) {
payload := NewPayload().Category("NEW_MESSAGE_CATEGORY")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"category":"NEW_MESSAGE_CATEGORY"}}`, string(b))
}

func TestMdm(t *testing.T) {
payload := NewPayload().Mdm("996ac527-9993-4a0a-8528-60b2b3c2f52b")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{},"mdm":"996ac527-9993-4a0a-8528-60b2b3c2f52b"}`, string(b))
}

func TestURLArgs(t *testing.T) {
payload := NewPayload().URLArgs([]string{"a", "b"})
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"url-args":["a","b"]}}`, string(b))
}

func TestCombined(t *testing.T) {
payload := NewPayload().Alert("hello").Badge(1).Sound("Default.caf").Custom("key", "val")
b, _ := json.Marshal(payload)
assert.Equal(t, `{"aps":{"alert":"hello","badge":1,"sound":"Default.caf"},"key":"val"}`, string(b))
}

0 comments on commit 8cb8a80

Please sign in to comment.