├── .gitignore ├── .travis.yml ├── Device.go ├── Device_test.go ├── Errors.go ├── LICENSE ├── Parameters.go ├── Placeholder.go ├── Plan.go ├── Plan_test.go ├── Product.go ├── ProductCategory.go ├── ProductCategory_test.go ├── ProductOption.go ├── ProductOption_test.go ├── Product_test.go ├── README.md ├── Request.go ├── Response.go ├── SMS.go ├── SMS_test.go ├── Session.go ├── Session_test.go ├── User.go └── json ├── device.json ├── devices.json ├── plan.json ├── plans.json ├── product.json ├── product_categories.json ├── product_options.json └── products.json /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | .DS_Store 3 | credentials.json 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go_import_path: hologram-temp 4 | 5 | go: 6 | - 1.x 7 | - 1.6 8 | - 1.7.x 9 | - master 10 | 11 | install: 12 | - go get github.com/hologram-io/hologram-go 13 | 14 | notifications: 15 | email: false 16 | slack: 17 | secure: XToigVpKXHupo90sIUcw9R1Y8e6zjATmYNY/mSqTkpGX57k5gfiewgXDzKF761i5sB+KGV8Odr2DCjrkPmgwYINqbXrvhioFK+KrDyEEkpCJrL5SdqklNLoe72pwvRYfU9S/NGZx92CW/OJLzwSJMolRYb6otDFCN4spuLYSiE7IZKVJjTRrsBbHGofsXeViG8Zn9wYRt9KNJNAqI/zRRsnL2hbBbEZifdZDvpsrz3SRDefl5YUAlA1qqThFXP/jhy39yRbH42dz+4CnzthmUNhllbmpTTYUsM1qdw8jnhU1MdxfA1SnfwkZI1IOGpwhsumhsB69RylWvN8aZ+MCEd4HcAIydTLV9uyAdrErUjda2illidiFSgG8YhocNUXzMruZbml0SO4mno3EX4l4OXKT+wT4N86bYE7EZlblwHvXnvjxXJTFRDkOUdDTj2SwXuxqg1wAP77Hdxavgs+X+Rx5zcU7Z8JJcqXaKeRc6lxImE/YYuoAN5p5aHArVh621/1oPKyqAsWm8WWHEMa3xkjYhIMzmBFdNGxCJMUJVknjjY5WHengBpF0CSP/snpC/g4ZUii0jsFO/6p1THEIiKuNkCyMTU6wvRqteypbEWvpdpHVk6Pmd/57hts7rCjt5cUoIobm1H4tfhkoIkoE1XUuQDW4k6Jaad5o5YSRaz0= 18 | -------------------------------------------------------------------------------- /Device.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | // Device object returned in the response. 10 | type Device map[string]interface{} 11 | 12 | // Devices is just a list of Device(s). 13 | type Devices []interface{} 14 | 15 | // GetDevices returns device details. 16 | func GetDevices() Devices { 17 | 18 | req := createGetRequest("/devices") 19 | 20 | resp, err := sendRequest(req) 21 | if err != nil { 22 | fmt.Printf("Could not send request: %v\n", err) 23 | os.Exit(1) 24 | } 25 | 26 | return unmarshallIntoArrayObject(resp) 27 | } 28 | 29 | // GetDevice returns a device detail based on the given deviceid. 30 | func GetDevice(deviceid int) Device { 31 | 32 | req := createGetRequest("/devices/" + strconv.Itoa(deviceid)) 33 | 34 | resp, err := sendRequest(req) 35 | 36 | if err != nil { 37 | fmt.Printf("Could not send request: %v\n", err) 38 | os.Exit(1) 39 | } 40 | 41 | return unmarshallIntoObject(resp) 42 | } 43 | 44 | // ClaimOwnershipAndActivateDevice claims ownership and activate the given device. 45 | func ClaimOwnershipAndActivateDevice(simnumber int) Device { 46 | 47 | var params Parameters 48 | req := createPostRequest("/cellular/sim_"+strconv.Itoa(simnumber)+"/claim", params) 49 | 50 | resp, err := sendRequest(req) 51 | if err != nil { 52 | fmt.Printf("Could not send request: %v\n", err) 53 | os.Exit(1) 54 | } 55 | 56 | return unmarshallIntoObject(resp) 57 | } 58 | 59 | // PurchaseAndAssignPhoneNumberToDevice purchases and assigns a phone number to the device. 60 | func PurchaseAndAssignPhoneNumberToDevice(deviceid int) Device { 61 | 62 | var params Parameters 63 | req := createPostRequest("/devices/"+strconv.Itoa(deviceid)+"/addnumber", params) 64 | 65 | resp, err := sendRequest(req) 66 | if err != nil { 67 | fmt.Printf("Could not send request: %v\n", err) 68 | os.Exit(1) 69 | } 70 | 71 | return unmarshallIntoObject(resp) 72 | } 73 | 74 | /////////////////////////////////////////////////// 75 | // GENERIC DEVICE GETTER FUNCTIONS 76 | /////////////////////////////////////////////////// 77 | 78 | // GetDeviceId returns the id. 79 | func (device Device) GetDeviceId() float64 { 80 | return device["id"].(float64) 81 | } 82 | 83 | // GetDeviceUserId returns the user id. 84 | func (device Device) GetDeviceUserId() float64 { 85 | return device["userid"].(float64) 86 | } 87 | 88 | // GetDeviceName returns the device name. 89 | func (device Device) GetDeviceName() string { 90 | return device["name"].(string) 91 | } 92 | 93 | // GetDeviceType returns the device type. 94 | func (device Device) GetDeviceType() string { 95 | return device["type"].(string) 96 | } 97 | 98 | // GetWhenCreated returns a UNIX timestamp of the creation time. 99 | func (device Device) GetWhenCreated() string { 100 | return device["whencreated"].(string) 101 | } 102 | 103 | // GetPhoneNumber returns a phone number. 104 | func (device Device) GetPhoneNumber() string { 105 | return device["phonenumber"].(string) 106 | } 107 | 108 | // GetTunnelable returns true if it is tunnelable. 109 | func (device Device) GetTunnelable() bool { 110 | return device["tunnelable"].(bool) 111 | } 112 | 113 | // TODO: links/cellular 114 | -------------------------------------------------------------------------------- /Device_test.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "github.com/hologram-io/hologram-go" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "testing" 9 | ) 10 | 11 | func TestGetDevices(t *testing.T) { 12 | 13 | file, e := ioutil.ReadFile("json/devices.json") 14 | if e != nil { 15 | fmt.Printf("Error opening file: %v\n", e) 16 | } 17 | 18 | var payload = HologramGo.Placeholder{} 19 | err := json.Unmarshal(file, &payload) 20 | if err != nil { 21 | fmt.Println("Unable to parse file") 22 | } 23 | 24 | var devices = payload["data"].([]interface{}) 25 | var device = (HologramGo.Device)(devices[0].(map[string]interface{})) 26 | 27 | // Check for expected device id 28 | expectedFloat := (float64)(84) 29 | returnedFloat := device.GetDeviceId() 30 | if expectedFloat != returnedFloat { 31 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 32 | } 33 | 34 | // Check for expected device user id 35 | expectedFloat = (float64)(4477) 36 | returnedFloat = device.GetDeviceUserId() 37 | if expectedFloat != returnedFloat { 38 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 39 | } 40 | 41 | // Check for expected device name 42 | expected := "Unnamed Device (90123)" 43 | returned := device.GetDeviceName() 44 | if expected != returned { 45 | t.Fatalf("Expected %s, got %s", expected, returned) 46 | } 47 | 48 | // Check for expected device type 49 | expected = "Unknown" 50 | returned = device.GetDeviceType() 51 | if expected != returned { 52 | t.Fatalf("Expected %s, got %s", expected, returned) 53 | } 54 | 55 | // Check for expected device creation date 56 | expected = "2016-06-06 21:51:16" 57 | returned = device.GetWhenCreated() 58 | if expected != returned { 59 | t.Fatalf("Expected %s, got %s", expected, returned) 60 | } 61 | 62 | // Check for expected device phone number 63 | expected = "" 64 | returned = device.GetPhoneNumber() 65 | if expected != returned { 66 | t.Fatalf("Expected %s, got %s", expected, returned) 67 | } 68 | } 69 | 70 | func TestGetDevice(t *testing.T) { 71 | 72 | file, e := ioutil.ReadFile("json/device.json") 73 | if e != nil { 74 | fmt.Printf("Error opening file: %v\n", e) 75 | } 76 | 77 | var payload = HologramGo.Placeholder{} 78 | err := json.Unmarshal(file, &payload) 79 | if err != nil { 80 | fmt.Println("Unable to parse file") 81 | } 82 | var device = (HologramGo.Device)(payload["data"].(map[string]interface{})) 83 | 84 | // Check for expected device id 85 | expectedFloat := (float64)(1) 86 | returnedFloat := device.GetDeviceId() 87 | if expectedFloat != returnedFloat { 88 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 89 | } 90 | 91 | // Check for expected device user id 92 | expectedFloat = (float64)(231) 93 | returnedFloat = device.GetDeviceUserId() 94 | if expectedFloat != returnedFloat { 95 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 96 | } 97 | 98 | // Check for expected device name 99 | expected := "Unnamed Device (91590)" 100 | returned := device.GetDeviceName() 101 | if expected != returned { 102 | t.Fatalf("Expected %s, got %s", expected, returned) 103 | } 104 | 105 | // Check for expected device type 106 | expected = "Unknown" 107 | returned = device.GetDeviceType() 108 | if expected != returned { 109 | t.Fatalf("Expected %s, got %s", expected, returned) 110 | } 111 | 112 | // Check for expected device creation date 113 | expected = "2015-03-25 03:12:13" 114 | returned = device.GetWhenCreated() 115 | if expected != returned { 116 | t.Fatalf("Expected %s, got %s", expected, returned) 117 | } 118 | 119 | // Check for expected device phone number 120 | expected = "" 121 | returned = device.GetPhoneNumber() 122 | if expected != returned { 123 | t.Fatalf("Expected %s, got %s", expected, returned) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Errors.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | // This file contains all Error types used within the package. 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | // Error returned if there was an issue parsing the response body. 10 | type ResponseError struct { 11 | Body string 12 | Code int 13 | } 14 | 15 | func NewResponseError(code int, body string) ResponseError { 16 | return ResponseError{Code: code, Body: body} 17 | } 18 | 19 | func (e ResponseError) Error() string { 20 | return fmt.Sprintf( 21 | "Unable to handle response (status code %d): `%v`", 22 | e.Code, 23 | e.Body) 24 | } 25 | 26 | type Error map[string]interface{} 27 | 28 | func (e Error) Code() int64 { 29 | return int64(e["code"].(float64)) 30 | } 31 | 32 | func (e Error) Message() string { 33 | return e["message"].(string) 34 | } 35 | 36 | func (e Error) Error() string { 37 | msg := "Error %v: %v" 38 | return fmt.Sprintf(msg, e.Code(), e.Message()) 39 | } 40 | 41 | type Errors map[string]interface{} 42 | 43 | func (e Errors) Error() string { 44 | var ( 45 | msg string = "" 46 | err Error 47 | ok bool 48 | ) 49 | if e["errors"] == nil { 50 | return msg 51 | } 52 | for _, val := range e["errors"].([]interface{}) { 53 | if err, ok = val.(map[string]interface{}); ok { 54 | msg += err.Error() + ". " 55 | } 56 | } 57 | return msg 58 | } 59 | 60 | func (e Errors) String() string { 61 | return e.Error() 62 | } 63 | 64 | func (e Errors) Errors() []Error { 65 | var errs = e["errors"].([]interface{}) 66 | var out = make([]Error, len(errs)) 67 | for i, val := range errs { 68 | out[i] = Error(val.(map[string]interface{})) 69 | } 70 | return out 71 | } 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2015 Konekt, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Parameters.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | type Parameters struct { 4 | items []string 5 | values []string 6 | } 7 | -------------------------------------------------------------------------------- /Placeholder.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | // This is just a placeholder for the map[string]interface{}, which is used 4 | // when unmarshalling data from a json object. 5 | type Placeholder map[string]interface{} 6 | -------------------------------------------------------------------------------- /Plan.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | // Plan is basically the returned Plan type in the response. 10 | type Plan map[string]interface{} 11 | 12 | // Plans is just a list of Plan(s). 13 | type Plans []interface{} 14 | 15 | // GetDeviceDataPlans returns device data plans. 16 | func GetDeviceDataPlans() Plans { 17 | 18 | req := createGetRequest("/plans/") 19 | 20 | resp, err := sendRequest(req) 21 | if err != nil { 22 | fmt.Printf("Could not send request: %v\n", err) 23 | os.Exit(1) 24 | } 25 | 26 | return unmarshallIntoArrayObject(resp) 27 | } 28 | 29 | // GetDeviceDataPlan returns a given device data plan. 30 | func GetDeviceDataPlan(planid int) Plan { 31 | 32 | req := createGetRequest("/plans/" + strconv.Itoa(planid)) 33 | 34 | resp, err := sendRequest(req) 35 | if err != nil { 36 | fmt.Printf("Could not send request: %v\n", err) 37 | os.Exit(1) 38 | } 39 | 40 | plans := unmarshallIntoArrayObject(resp) 41 | 42 | return (Plan)(plans[0].(map[string]interface{})) 43 | } 44 | 45 | /////////////////////////////////////////////////// 46 | // GENERIC PLAN GETTER FUNCTIONS 47 | /////////////////////////////////////////////////// 48 | 49 | // GetDataPlanId returns the data plan id. 50 | func (plan Plan) GetDataPlanId() float64 { 51 | return plan["id"].(float64) 52 | } 53 | 54 | // GetDataPlanPartnerId returns the data plan partner id. 55 | func (plan Plan) GetDataPlanPartnerId() float64 { 56 | return plan["partnerid"].(float64) 57 | } 58 | 59 | // GetDataPlanName returns the data plan name. 60 | func (plan Plan) GetDataPlanName() string { 61 | return plan["name"].(string) 62 | } 63 | 64 | // GetDataPlanDescription returns the data plan description. 65 | func (plan Plan) GetDataPlanDescription() string { 66 | return plan["description"].(string) 67 | } 68 | 69 | // GetDataPlanSize returns the data size. 70 | func (plan Plan) GetDataPlanSize() float64 { 71 | return plan["data"].(float64) 72 | } 73 | 74 | // IsDataPlanRecurring returns true if it is recurring. 75 | func (plan Plan) IsDataPlanRecurring() bool { 76 | return plan["recurring"].(bool) 77 | } 78 | 79 | // IsDataPlanEnabled returns true if the data plan is enabled. 80 | func (plan Plan) IsDataPlanEnabled() bool { 81 | return plan["enabled"].(bool) 82 | } 83 | 84 | // GetDataPlanBillingPeriod returns the billing period. 85 | func (plan Plan) GetDataPlanBillingPeriod() float64 { 86 | return plan["billingperiod"].(float64) 87 | } 88 | 89 | // GetDataPlanTrialDays returns the number of trial days left. 90 | func (plan Plan) GetDataPlanTrialDays() float64 { 91 | return plan["trialdays"].(float64) 92 | } 93 | 94 | // GetDataPlanTemplateId returns the data plan template id. 95 | func (plan Plan) GetDataPlanTemplateId() float64 { 96 | return plan["templateid"].(float64) 97 | } 98 | 99 | // GetDataPlanCarrierId returns the carrier id of the data plan. 100 | func (plan Plan) GetDataPlanCarrierId() float64 { 101 | return plan["carrierid"].(float64) 102 | } 103 | 104 | // GetDataPlanGroupId returns the groupid of the data plan. 105 | func (plan Plan) GetDataPlanGroupId() float64 { 106 | return plan["groupid"].(float64) 107 | } 108 | -------------------------------------------------------------------------------- /Plan_test.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/hologram-io/hologram-go" 6 | "fmt" 7 | "io/ioutil" 8 | "testing" 9 | ) 10 | 11 | func TestGetDeviceDataPlan(t *testing.T) { 12 | 13 | file, e := ioutil.ReadFile("json/plan.json") 14 | if e != nil { 15 | fmt.Printf("Error opening file: %v\n", e) 16 | } 17 | 18 | var payload = HologramGo.Placeholder{} 19 | err := json.Unmarshal(file, &payload) 20 | if err != nil { 21 | fmt.Println("Unable to parse file") 22 | } 23 | var plans = (payload["data"].([]interface{})) 24 | var plan = (HologramGo.Plan)(plans[0].(map[string]interface{})) 25 | 26 | // Test for data plan id 27 | expectedFloat := (float64)(51) 28 | returnedFloat := plan.GetDataPlanId() 29 | if expectedFloat != returnedFloat { 30 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 31 | } 32 | 33 | // Test for data plan partner id. 34 | expectedFloat = (float64)(1) 35 | returnedFloat = plan.GetDataPlanPartnerId() 36 | if expectedFloat != returnedFloat { 37 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 38 | } 39 | 40 | // Test for data plan name. 41 | expectedString := "1 MB" 42 | returnedString := plan.GetDataPlanName() 43 | if expectedString != returnedString { 44 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 45 | } 46 | 47 | // Test for data plan subscription 48 | expectedString = "" 49 | returnedString = plan.GetDataPlanDescription() 50 | if expectedString != returnedString { 51 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 52 | } 53 | 54 | // Test for data plan size 55 | expectedFloat = (float64)(1000000) 56 | returnedFloat = plan.GetDataPlanSize() 57 | if expectedFloat != returnedFloat { 58 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 59 | } 60 | 61 | // Test for data plan billing period 62 | expectedFloat = (float64)(24) 63 | returnedFloat = plan.GetDataPlanBillingPeriod() 64 | if expectedFloat != returnedFloat { 65 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 66 | } 67 | 68 | // Test for data plan carrier id. 69 | expectedFloat = (float64)(1) 70 | returnedFloat = plan.GetDataPlanCarrierId() 71 | if expectedFloat != returnedFloat { 72 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Product.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | // Product implements the Product type returned in the response. 10 | type Product map[string]interface{} 11 | 12 | // Products is just a list of Product(s). 13 | type Products []interface{} 14 | 15 | // GetProducts returns product details. 16 | func GetProducts() Products { 17 | 18 | req := createGetRequest("/products/") 19 | 20 | resp, err := sendRequest(req) 21 | if err != nil { 22 | fmt.Printf("Could not send request: %v\n", err) 23 | os.Exit(1) 24 | } 25 | 26 | return unmarshallIntoArrayObject(resp) 27 | } 28 | 29 | // GetProduct returns product details response. 30 | func GetProduct(id int) Product { 31 | 32 | req := createGetRequest("/products/" + strconv.Itoa(id)) 33 | 34 | resp, err := sendRequest(req) 35 | if err != nil { 36 | fmt.Printf("Could not send request: %v\n", err) 37 | os.Exit(1) 38 | } 39 | 40 | return unmarshallIntoObject(resp) 41 | } 42 | 43 | /////////////////////////////////////////////////// 44 | // GENERIC PRODUCT GETTER FUNCTIONS 45 | /////////////////////////////////////////////////// 46 | 47 | // GetProductId returns the id of the product. 48 | func (product Product) GetProductId() float64 { 49 | return product["id"].(float64) 50 | } 51 | 52 | // GetProductSku returns the sku of the product. 53 | func (product Product) GetProductSku() string { 54 | return product["sku"].(string) 55 | } 56 | 57 | // GetProductName returns the name of the product. 58 | func (product Product) GetProductName() string { 59 | return product["name"].(string) 60 | } 61 | 62 | // GetProductDescription returns the description of the product. 63 | func (product Product) GetProductDescription() string { 64 | return product["description"].(string) 65 | } 66 | 67 | // GetProductPrice returns the price of the product. 68 | func (product Product) GetProductPrice() string { 69 | return product["price"].(string) 70 | } 71 | 72 | // GetProductImageUrl returns the sku of the product. 73 | func (product Product) GetProductImageUrl() string { 74 | return product["imageurl"].(string) 75 | } 76 | 77 | // GetProductInvoiceDescription returns the invoice description of the product. 78 | func (product Product) GetProductInvoiceDescription() string { 79 | return product["invoice_description"].(string) 80 | } 81 | 82 | // GetProductPreorderDetails returns the invoice description of the product. 83 | func (product Product) GetProductPreorderDetails() string { 84 | return product["preorder_details"].(string) 85 | } 86 | -------------------------------------------------------------------------------- /ProductCategory.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | type ProductCategory map[string]interface{} 9 | 10 | type ProductCategories []interface{} 11 | 12 | // EFFECTS: Returns product categories. 13 | func GetProductCategories() ProductCategories { 14 | 15 | req := createGetRequest("/products/categories/") 16 | 17 | resp, err := sendRequest(req) 18 | if err != nil { 19 | fmt.Printf("Could not send request: %v\n", err) 20 | os.Exit(1) 21 | } 22 | 23 | return unmarshallIntoArrayObject(resp) 24 | } 25 | 26 | /////////////////////////////////////////////////// 27 | // GENERIC PRODUCT CATEGORIES GETTER FUNCTIONS 28 | /////////////////////////////////////////////////// 29 | 30 | func (productCategory ProductCategory) GetProductCategoryName() string { 31 | return productCategory["category"].(string) 32 | } 33 | 34 | // EFFECTS: Returns the sku of the product option. 35 | func (productCategory ProductCategory) GetProductIdsFromCategory() []interface{} { 36 | 37 | return productCategory["productids"].([]interface{}) 38 | } 39 | -------------------------------------------------------------------------------- /ProductCategory_test.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "github.com/hologram-io/hologram-go" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "testing" 9 | ) 10 | 11 | func TestGetProductCategories(t *testing.T) { 12 | 13 | file, e := ioutil.ReadFile("json/product_categories.json") 14 | if e != nil { 15 | fmt.Printf("Error opening file: %v\n", e) 16 | } 17 | 18 | var payload = HologramGo.Placeholder{} 19 | err := json.Unmarshal(file, &payload) 20 | if err != nil { 21 | fmt.Println("Unable to parse file") 22 | } 23 | 24 | // Test the first product 25 | var productCategories = (payload["data"].([]interface{})) 26 | var productCategory = (HologramGo.ProductCategory)(productCategories[0].(map[string]interface{})) 27 | 28 | // Check for expected category. 29 | expectedString := "accessories" 30 | returnedString := productCategory.GetProductCategoryName() 31 | if expectedString != returnedString { 32 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 33 | } 34 | 35 | // Check for expected category. 36 | //expectedIntSlice := []int{15, 19, 11, 10, 9, 8, 7, 23} 37 | //returnedIntSlice := productCategory.GetProductIdsFromCategory() 38 | 39 | //// Length check 40 | //if len(expectedIntSlice) != len(returnedIntSlice) { 41 | // t.Fatalf("Expected length %s, got %s", expectedString, returnedString) 42 | //} 43 | 44 | //for i := range expectedIntSlice { 45 | 46 | // if expectedIntSlice[i] != returnedIntSlice[i] { 47 | // t.Fatalf("Expected %s, got %s", expectedString, returnedString) 48 | // } 49 | //} 50 | } 51 | -------------------------------------------------------------------------------- /ProductOption.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // ProductOption implements the product option returned from the response. 9 | type ProductOption map[string]interface{} 10 | 11 | // ProductOptions is just a list of ProductOption(s) 12 | type ProductOptions []interface{} 13 | 14 | // GetProductOptions returns product options. 15 | func GetProductOptions() ProductOptions { 16 | 17 | req := createGetRequest("/products/options/") 18 | 19 | resp, err := sendRequest(req) 20 | if err != nil { 21 | fmt.Printf("Could not send request: %v\n", err) 22 | os.Exit(1) 23 | } 24 | 25 | return unmarshallIntoArrayObject(resp) 26 | } 27 | 28 | /////////////////////////////////////////////////// 29 | // PRODUCT OPTION GETTER FUNCTIONS 30 | /////////////////////////////////////////////////// 31 | 32 | // GetProductIdFromOption returns the product id. 33 | func (productOption ProductOption) GetProductIdFromOption() float64 { 34 | return productOption["productid"].(float64) 35 | } 36 | 37 | // GetProductOptionAppendSku returns the sku of the product option. 38 | func (productOption ProductOption) GetProductOptionAppendSku() string { 39 | return productOption["appendsku"].(string) 40 | } 41 | 42 | // GetProductOptionPriceChang returns the price change of the product option. 43 | func (productOption ProductOption) GetProductOptionPriceChange() string { 44 | return productOption["pricechange"].(string) 45 | } 46 | 47 | // GetProductOptionDescription returns the description of the product option. 48 | func (productOption ProductOption) GetProductOptionDescription() string { 49 | return productOption["description"].(string) 50 | } 51 | 52 | // GetProductOptionInvoiceDescription returns the invoice description of the product option. 53 | func (productOption ProductOption) GetProductOptionInvoiceDescription() string { 54 | return productOption["invoice_description"].(string) 55 | } 56 | -------------------------------------------------------------------------------- /ProductOption_test.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "github.com/hologram-io/hologram-go" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "testing" 9 | ) 10 | 11 | // TODO: Add product options and categories. 12 | func TestGetProductOptions(t *testing.T) { 13 | 14 | file, e := ioutil.ReadFile("json/product_options.json") 15 | if e != nil { 16 | fmt.Printf("Error opening file: %v\n", e) 17 | } 18 | 19 | var payload = HologramGo.Placeholder{} 20 | err := json.Unmarshal(file, &payload) 21 | if err != nil { 22 | fmt.Println("Unable to parse file") 23 | } 24 | 25 | // Test the first product 26 | var productOptions = (payload["data"].([]interface{})) 27 | var productOption = (HologramGo.ProductOption)(productOptions[1].(map[string]interface{})) 28 | 29 | // Check for expected product id 30 | expectedFloat := (float64)(2) 31 | returnedFloat := productOption.GetProductIdFromOption() 32 | if expectedFloat != returnedFloat { 33 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 34 | } 35 | 36 | expectedString := "5DASH" 37 | returnedString := productOption.GetProductOptionAppendSku() 38 | if expectedString != returnedString { 39 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 40 | } 41 | 42 | expectedString = "0.00" 43 | returnedString = productOption.GetProductOptionPriceChange() 44 | if expectedString != returnedString { 45 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 46 | } 47 | 48 | expectedString = "5 Dashes" 49 | returnedString = productOption.GetProductOptionInvoiceDescription() 50 | if expectedString != returnedString { 51 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Product_test.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "github.com/hologram-io/hologram-go" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "testing" 9 | ) 10 | 11 | // func TestGetProducts(t *testing.T) { 12 | 13 | // file, e := ioutil.ReadFile("json/device.json") 14 | // if e != nil { 15 | // fmt.Printf("Error opening file: %v\n", e) 16 | // } 17 | 18 | // var payload = HologramGo.Placeholder{} 19 | // err := json.Unmarshal(file, &payload) 20 | // if err != nil { 21 | // fmt.Println("Unable to parse file") 22 | // } 23 | // var device = (HologramGo.Device)(payload["data"].(map[string]interface{})) 24 | 25 | // // Check for expected device id 26 | // expectedFloat := (float64)(1) 27 | // returnedFloat := device.GetDeviceId() 28 | // if expectedFloat != returnedFloat { 29 | // t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 30 | // } 31 | 32 | // } 33 | 34 | func TestGetProduct(t *testing.T) { 35 | 36 | file, e := ioutil.ReadFile("json/product.json") 37 | if e != nil { 38 | fmt.Printf("Error opening file: %v\n", e) 39 | } 40 | 41 | var payload = HologramGo.Placeholder{} 42 | err := json.Unmarshal(file, &payload) 43 | if err != nil { 44 | fmt.Println("Unable to parse file") 45 | } 46 | var product = (HologramGo.Product)(payload["data"].(map[string]interface{})) 47 | 48 | // Check for expected product id 49 | expectedFloat := (float64)(1) 50 | returnedFloat := product.GetProductId() 51 | if expectedFloat != returnedFloat { 52 | t.Fatalf("Expected %s, got %s", expectedFloat, returnedFloat) 53 | } 54 | 55 | expectedString := "SIM" 56 | returnedString := product.GetProductSku() 57 | if expectedString != returnedString { 58 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 59 | } 60 | 61 | expectedString = "SIM Card" 62 | returnedString = product.GetProductName() 63 | if expectedString != returnedString { 64 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 65 | } 66 | 67 | expectedString = "The Hologram Global SIM Card. Comes in a variety of sizes for any application. (Pick your data plan when you go to activate the SIM.)" 68 | returnedString = product.GetProductDescription() 69 | if expectedString != returnedString { 70 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 71 | } 72 | 73 | expectedString = "5.00" 74 | returnedString = product.GetProductPrice() 75 | if expectedString != returnedString { 76 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 77 | } 78 | 79 | expectedString = "https://dashboard.hologram.io/img/sim_card.jpg" 80 | returnedString = product.GetProductImageUrl() 81 | if expectedString != returnedString { 82 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 83 | } 84 | 85 | expectedString = "Global SIM Card" 86 | returnedString = product.GetProductInvoiceDescription() 87 | if expectedString != returnedString { 88 | t.Fatalf("Expected %s, got %s", expectedString, returnedString) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Hologram-Go-Library 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/hologram-io/hologram-go)](https://goreportcard.com/report/github.com/hologram-io/hologram-go) 4 | [![Build Status](https://travis-ci.org/hologram-io/hologram-go.svg?branch=master)](https://travis-ci.org/hologram-io/hologram-go) 5 | 6 | ## Introduction 7 | This is a library built for using our REST APIs. 8 | 9 | ## Installation 10 | 11 | One nice thing about Go is how easy it is to work with packages. 12 | First, run: 13 | 14 | ```go 15 | go get github.com/hologram-io/hologram-go 16 | ``` 17 | 18 | All you need to do after that is add this snippet of code in your source: 19 | 20 | ``` 21 | import ( 22 | 23 | "github.com/hologram-io/hologram-go" 24 | 25 | ) 26 | ``` 27 | 28 | in your main folder. 29 | 30 | ## Unit Tests 31 | Yay! you're ready for some good testing. All of the test cases are located in the 32 | top `test` directory. Mocked data (in JSON) are in the `test/json` directory. To run a unit test, 33 | just type: 34 | 35 | ``` 36 | go test 37 | ``` 38 | 39 | ## Support 40 | Please feel free to [reach out to us](https://hologram.io/) if you have any questions/concerns. 41 | 42 | ## Credits 43 | Special thanks to the amazing work that @kurrik put in his 44 | [twittergo](https://github.com/kurrik/roomanna/) library. The Errors and Parse 45 | interface/functions were taken from there and modified for our needs. 46 | -------------------------------------------------------------------------------- /Request.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | // This file contains all HTTP Response related behavior. 4 | 5 | import ( 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "log" 10 | "net/http" 11 | "net/http/cookiejar" 12 | "net/url" 13 | "os" 14 | "strings" 15 | 16 | "golang.org/x/net/publicsuffix" 17 | ) 18 | 19 | const HOLOGRAM_REST_API_BASEURL = "https://dashboard.hologram.io/api/1" 20 | 21 | var err error 22 | 23 | // These two variables will store user's username and password. 24 | var username string 25 | var password string 26 | 27 | // REQUIRES: User's username and password. 28 | // EFFECTS: Initializes the user's username and password state to be used in each 29 | // basic authenticated API call. 30 | func InitializeUsernameAndPassword(credentialFile string) { 31 | 32 | file, e := ioutil.ReadFile(credentialFile) 33 | if e != nil { 34 | fmt.Printf("Error opening file: %v\n", e) 35 | } 36 | 37 | type Payload map[string]interface{} 38 | var jsonpayload = Payload{} 39 | json.Unmarshal(file, &jsonpayload) 40 | 41 | username = jsonpayload["username"].(string) 42 | password = jsonpayload["password"].(string) 43 | } 44 | 45 | // EFFECTS: Sends a HTTP request through this instance's HTTP client. 46 | func sendRequest(req *http.Request) (response *Response, err error) { 47 | 48 | options := cookiejar.Options{ 49 | PublicSuffixList: publicsuffix.List, 50 | } 51 | 52 | jar, err := cookiejar.New(&options) 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | 57 | client := &http.Client{ 58 | Jar: jar, 59 | } 60 | 61 | req.SetBasicAuth(username, password) 62 | resp, err := client.Do(req) 63 | 64 | response = (*Response)(resp) 65 | return response, err 66 | } 67 | 68 | // REQUIRES: The endpoint of the API call. 69 | // EFFECTS: Creates and populates a HTTP GET request. 70 | func createGetRequest(derivedUrl string) (req *http.Request) { 71 | 72 | req, err = http.NewRequest("GET", HOLOGRAM_REST_API_BASEURL+derivedUrl, nil) 73 | if err != nil { 74 | fmt.Printf("Could not parse request: %v\n", err) 75 | os.Exit(1) 76 | } 77 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 78 | 79 | return req 80 | } 81 | 82 | // REQUIRES: The endpoint of the API call, parameter names and values. 83 | // EFFECTS: Creates and populates a HTTP POST request. 84 | func createPostRequest(derivedUrl string, params Parameters) (req *http.Request) { 85 | 86 | data := url.Values{} 87 | 88 | // Set all body parameters here. 89 | for i, _ := range params.items { 90 | data.Set(params.items[i], params.values[i]) 91 | } 92 | 93 | body := strings.NewReader(data.Encode()) 94 | 95 | req, err = http.NewRequest("POST", HOLOGRAM_REST_API_BASEURL+derivedUrl, body) 96 | fmt.Println(HOLOGRAM_REST_API_BASEURL + derivedUrl) 97 | if err != nil { 98 | fmt.Printf("Could not parse request: %v\n", err) 99 | os.Exit(1) 100 | } 101 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 102 | 103 | return req 104 | } 105 | -------------------------------------------------------------------------------- /Response.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | // This file contains all HTTP Response related behavior. 4 | 5 | import ( 6 | "encoding/json" 7 | "fmt" 8 | "io" 9 | "io/ioutil" 10 | "net/http" 11 | "os" 12 | ) 13 | 14 | // HTTP status codes 15 | const ( 16 | STATUS_OK = 200 17 | STATUS_CREATED = 201 18 | STATUS_ACCEPTED = 202 19 | STATUS_NO_CONTENT = 204 20 | STATUS_INVALID = 400 21 | STATUS_UNAUTHORIZED = 401 22 | STATUS_FORBIDDEN = 403 23 | STATUS_NOTFOUND = 404 24 | STATUS_LIMIT = 429 25 | STATUS_GATEWAY = 502 26 | ) 27 | 28 | // EFFECTS: Takes in the response and unmarshalls it into the appropriate interface. 29 | func unmarshallIntoObject(resp *Response) map[string]interface{} { 30 | 31 | var payload = Placeholder{} 32 | err = resp.parsePayload(&payload) 33 | // error handling 34 | if err != nil { 35 | fmt.Printf("Problem parsing response: %v\n", err) 36 | os.Exit(1) 37 | } 38 | 39 | return payload["data"].(map[string]interface{}) 40 | } 41 | 42 | // EFFECTS: Takes in the response and unmarshalls into an array object. 43 | func unmarshallIntoArrayObject(resp *Response) []interface{} { 44 | 45 | var payload = Placeholder{} 46 | err = resp.parsePayload(&payload) 47 | // error handling 48 | if err != nil { 49 | fmt.Printf("Problem parsing response: %v\n", err) 50 | os.Exit(1) 51 | } 52 | 53 | return payload["data"].([]interface{}) 54 | } 55 | 56 | type Response http.Response 57 | 58 | func (response Response) parseBody() (b []byte, err error) { 59 | 60 | var ( 61 | //header string 62 | reader io.Reader 63 | ) 64 | 65 | defer response.Body.Close() 66 | reader = response.Body 67 | 68 | b, err = ioutil.ReadAll(reader) 69 | 70 | return b, err 71 | } 72 | 73 | // EFFECTS: Populates the given object based on the returned response 74 | func (response Response) parsePayload(out interface{}) (err error) { 75 | 76 | var b []byte 77 | 78 | statusCode := response.StatusCode 79 | 80 | if statusCode == STATUS_UNAUTHORIZED || statusCode == STATUS_NOTFOUND || 81 | statusCode == STATUS_GATEWAY || statusCode == STATUS_FORBIDDEN || 82 | statusCode == STATUS_INVALID { 83 | 84 | e := &Errors{} 85 | b, err = response.parseBody() 86 | if err != nil { 87 | return err 88 | } 89 | 90 | err = json.Unmarshal(b, e) 91 | 92 | if err != nil { 93 | err = NewResponseError(response.StatusCode, string(b)) 94 | } else { 95 | err = *e 96 | } 97 | } else if statusCode == STATUS_CREATED || statusCode == STATUS_ACCEPTED || 98 | statusCode == STATUS_OK { 99 | b, err = response.parseBody() 100 | if err != nil { 101 | return err 102 | } 103 | err = json.Unmarshal(b, out) 104 | if err == io.EOF { 105 | err = nil 106 | } 107 | } else { 108 | b, err = response.parseBody() 109 | if err != nil { 110 | return err 111 | } 112 | err = NewResponseError(response.StatusCode, string(b)) 113 | } 114 | return err 115 | } 116 | -------------------------------------------------------------------------------- /SMS.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // SMS implements the SMS type returned from the response. 9 | type SMS map[string]interface{} 10 | 11 | // SendSMSToDevice sends an SMS to a device and returns the response. 12 | func SendSMSToDevice(deviceid int, phonenumber string) SMS { 13 | 14 | var params Parameters 15 | req := createPostRequest("/sms/incoming", params) 16 | 17 | resp, err := sendRequest(req) 18 | if err != nil { 19 | fmt.Printf("Could not send request: %v\n", err) 20 | os.Exit(1) 21 | } 22 | 23 | return unmarshallIntoObject(resp) 24 | } 25 | -------------------------------------------------------------------------------- /SMS_test.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import "testing" 4 | 5 | func TestGetProductSMS(t *testing.T) { 6 | //expectedProductName := "SIM Card" 7 | 8 | //var product = GetProduct(1) 9 | 10 | //productName := product.GetProductName() 11 | 12 | //if expectedProductName != productName { 13 | //t.Fatalf("Expected %s, got %s", expectedProductName, product.GetProductName()) 14 | //} 15 | } 16 | -------------------------------------------------------------------------------- /Session.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // Session implements the Session type returned from the response. 9 | type Session map[string]interface{} 10 | 11 | // CreateSession creates a new session. 12 | func CreateSession(email string, password string) Session { 13 | 14 | var params Parameters 15 | req := createPostRequest("/auth/session", params) 16 | 17 | resp, err := sendRequest(req) 18 | if err != nil { 19 | fmt.Printf("Could not send request: %v\n", err) 20 | os.Exit(1) 21 | } 22 | 23 | return unmarshallIntoObject(resp) 24 | } 25 | 26 | // TODO: func (session Session) end // without sesskey. 27 | 28 | // EndSession destroys a session based on the given sesskey. 29 | func EndSession(sesskey string) Session { 30 | 31 | var params Parameters 32 | req := createPostRequest("/auth/sessiondestroy", params) 33 | 34 | resp, err := sendRequest(req) 35 | if err != nil { 36 | fmt.Printf("Could not send request: %v\n", err) 37 | os.Exit(1) 38 | } 39 | 40 | return unmarshallIntoObject(resp) 41 | } 42 | -------------------------------------------------------------------------------- /Session_test.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import "testing" 4 | 5 | func TestGetProductSession(t *testing.T) { 6 | //expectedProductName := "SIM Card" 7 | 8 | //var product = GetProduct(1) 9 | 10 | //productName := product.GetProductName() 11 | 12 | //if expectedProductName != productName { 13 | //t.Fatalf("Expected %s, got %s", expectedProductName, product.GetProductName()) 14 | //} 15 | } 16 | -------------------------------------------------------------------------------- /User.go: -------------------------------------------------------------------------------- 1 | package HologramGo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | // Users is just a list of User(s). 10 | type Users []User 11 | 12 | // User implements the User type returned from the response. 13 | type User map[string]interface{} 14 | 15 | // CreateUser makes a HTTP Post call to create a new user. 16 | func CreateUser(id int) User { 17 | 18 | var params Parameters 19 | req := createPostRequest("/users/", params) 20 | 21 | resp, err := sendRequest(req) 22 | if err != nil { 23 | fmt.Printf("Could not send request: %v\n", err) 24 | os.Exit(1) 25 | } 26 | 27 | return unmarshallIntoObject(resp) 28 | } 29 | 30 | // GetUserAccountDetails returns the user's account details based on the given userid. 31 | func GetUserAccountDetails(id int) User { 32 | 33 | req := createGetRequest("/users/" + strconv.Itoa(id)) 34 | 35 | resp, err := sendRequest(req) 36 | if err != nil { 37 | fmt.Printf("Could not send request: %v\n", err) 38 | os.Exit(1) 39 | } 40 | 41 | return unmarshallIntoObject(resp) 42 | } 43 | 44 | // ChangeUserPassword changes the user's password. 45 | func ChangeUserPassword(password string) User { 46 | 47 | var params Parameters 48 | req := createPostRequest("/users/me/password/", params) 49 | 50 | resp, err := sendRequest(req) 51 | if err != nil { 52 | fmt.Printf("Could not send request: %v\n", err) 53 | os.Exit(1) 54 | } 55 | 56 | return unmarshallIntoObject(resp) 57 | } 58 | 59 | // GetUserAddresses retrieves user addresses. 60 | func GetUserAddresses() User { 61 | 62 | req := createGetRequest("/users/me/addresses") 63 | 64 | resp, err := sendRequest(req) 65 | if err != nil { 66 | fmt.Printf("Could not send request: %v\n", err) 67 | os.Exit(1) 68 | } 69 | 70 | return unmarshallIntoObject(resp) 71 | } 72 | 73 | // AddUserAddress adds a new address to the user. 74 | func AddUserAddress() User { 75 | 76 | var params Parameters 77 | req := createPostRequest("/users/me/addresses", params) 78 | 79 | resp, err := sendRequest(req) 80 | if err != nil { 81 | fmt.Printf("Could not send request: %v\n", err) 82 | os.Exit(1) 83 | } 84 | 85 | return unmarshallIntoObject(resp) 86 | } 87 | 88 | // GetAPIKey returns the user's API key. 89 | func GetAPIKey() User { 90 | 91 | req := createGetRequest("/users/me/apikey") 92 | 93 | resp, err := sendRequest(req) 94 | if err != nil { 95 | fmt.Printf("Could not send request: %v\n", err) 96 | os.Exit(1) 97 | } 98 | 99 | return unmarshallIntoObject(resp) 100 | } 101 | 102 | // GenerateNewAPIKey generates a new API key. 103 | func GenerateNewAPIKey() User { 104 | 105 | var params Parameters 106 | req := createPostRequest("/users/me/apikey", params) 107 | 108 | resp, err := sendRequest(req) 109 | if err != nil { 110 | fmt.Printf("Could not send request: %v\n", err) 111 | os.Exit(1) 112 | } 113 | 114 | return unmarshallIntoObject(resp) 115 | } 116 | 117 | /////////////////////////////////////////////////// 118 | // GENERIC USER GETTER FUNCTIONS 119 | /////////////////////////////////////////////////// 120 | 121 | // GetUserFirstName returns the first name of the given user. 122 | func (user User) GetUserFirstName() string { 123 | return user["first"].(string) 124 | } 125 | 126 | // GetUserLastName returns the last name of the given user. 127 | func (user User) GetUserLastName() string { 128 | return user["last"].(string) 129 | } 130 | 131 | // GetUserRole returns the role of the user. 132 | func (user User) GetUserRole() string { 133 | return user["role"].(string) 134 | } 135 | 136 | // GetUserAPIKey returns the user's API key. 137 | func (user User) GetUserAPIKey() string { 138 | return user["apikey"].(string) 139 | } 140 | -------------------------------------------------------------------------------- /json/device.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": { 4 | "id": 1, 5 | "userid": 231, 6 | "name": "Unnamed Device (91590)", 7 | "type": "Unknown", 8 | "whencreated": "2015-03-25 03:12:13", 9 | "phonenumber": "", 10 | "tunnelable": 0, 11 | "tags": [], 12 | "links": { 13 | "cellular": [ 14 | { 15 | "id": 6, 16 | "sim": "89314404000097091590", 17 | "imsi": 204043251884852, 18 | "carrierid": 1, 19 | "state": "DEAD", 20 | "whenclaimed": "2014-12-20 00:20:12", 21 | "whenexpires": "2015-06-18 00:20:12", 22 | "overagelimit": -1, 23 | "last_network_used": "", 24 | "last_connect_time": "", 25 | "cur_billing_data_used": 0, 26 | "apn": "internetd.gdsp (no user, no pw)", 27 | "plan": { 28 | "id": 28, 29 | "tier": 1, 30 | "name": "1 MB + 30-day FREE TRIAL", 31 | "data": 1000000, 32 | "cost": "1.73", 33 | "overage": "2.00", 34 | "sms": "0.19" 35 | } 36 | } 37 | ] 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /json/devices.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": [ 4 | { 5 | "id": 84, 6 | "userid": 4477, 7 | "name": "Unnamed Device (90123)", 8 | "type": "Unknown", 9 | "whencreated": "2016-06-06 21:51:16", 10 | "phonenumber": "", 11 | "tunnelable": 0, 12 | "hidden": 0, 13 | "tags": [ 14 | { 15 | "id": 15, 16 | "name": "wassup4" 17 | }, 18 | { 19 | "id": 8, 20 | "name": "wassup2" 21 | }, 22 | { 23 | "id": 7, 24 | "name": "wassup" 25 | }, 26 | { 27 | "id": 16, 28 | "name": "wassup6" 29 | }, 30 | { 31 | "id": 9, 32 | "name": "wassup3" 33 | }, 34 | { 35 | "id": 14, 36 | "name": "wassup1" 37 | } 38 | ], 39 | "links": { 40 | "cellular": [ 41 | { 42 | "id": 39, 43 | "sim": "1234567890123", 44 | "imsi": 1234567890123, 45 | "carrierid": 1, 46 | "state": "LIVE", 47 | "whenclaimed": "2016-06-06 21:51:16", 48 | "whenexpires": "2016-07-06 21:51:16", 49 | "overagelimit": -1, 50 | "last_network_used": "", 51 | "last_connect_time": "", 52 | "cur_billing_data_used": 0, 53 | "apn": "test", 54 | "plan": { 55 | "id": 100, 56 | "tier": 1, 57 | "name": "TEMP PLAN", 58 | "data": 0, 59 | "cost": "123.00", 60 | "overage": "123.00", 61 | "sms": "123.00" 62 | } 63 | } 64 | ] 65 | } 66 | }, 67 | { 68 | "id": 83, 69 | "userid": 477, 70 | "name": "Unnamed Device (67890)", 71 | "type": "Unknown", 72 | "whencreated": "2016-06-06 19:15:07", 73 | "phonenumber": "", 74 | "tunnelable": 0, 75 | "hidden": 0, 76 | "tags": [], 77 | "links": { 78 | "cellular": [ 79 | { 80 | "id": 38, 81 | "sim": "1234567890", 82 | "imsi": 1234567890, 83 | "carrierid": 1, 84 | "state": "LIVE-PENDING", 85 | "whenclaimed": "2016-06-06 19:15:07", 86 | "whenexpires": "2018-05-27 19:15:07", 87 | "overagelimit": -1, 88 | "last_network_used": "", 89 | "last_connect_time": "", 90 | "cur_billing_data_used": 0, 91 | "apn": "test", 92 | "plan": { 93 | "id": 52, 94 | "tier": 1, 95 | "name": "3 MB", 96 | "data": 3000000, 97 | "cost": "3.40", 98 | "overage": "0.20", 99 | "sms": "0.19" 100 | } 101 | } 102 | ] 103 | } 104 | }, 105 | { 106 | "id": 82, 107 | "userid": 477, 108 | "name": "Unnamed Device (00001)", 109 | "type": "Unknown", 110 | "whencreated": "2016-05-04 14:41:28", 111 | "phonenumber": "", 112 | "tunnelable": 0, 113 | "hidden": 0, 114 | "tags": [], 115 | "links": { 116 | "cellular": [ 117 | { 118 | "id": 37, 119 | "sim": "99900001", 120 | "imsi": 1000001, 121 | "carrierid": 1, 122 | "state": "LIVE", 123 | "whenclaimed": "2016-05-04 14:41:28", 124 | "whenexpires": "2018-04-24 14:41:28", 125 | "overagelimit": 10, 126 | "last_network_used": "", 127 | "last_connect_time": "", 128 | "cur_billing_data_used": 0, 129 | "apn": "test", 130 | "plan": { 131 | "id": 52, 132 | "tier": 1, 133 | "name": "3 MB", 134 | "data": 3000000, 135 | "cost": "3.40", 136 | "overage": "0.20", 137 | "sms": "0.19" 138 | } 139 | } 140 | ] 141 | } 142 | }, 143 | { 144 | "id": 81, 145 | "userid": 477, 146 | "name": "Unnamed Device (09115)", 147 | "type": "Unknown", 148 | "whencreated": "2016-04-26 20:31:42", 149 | "phonenumber": "", 150 | "tunnelable": 0, 151 | "hidden": 0, 152 | "tags": [], 153 | "links": { 154 | "cellular": [] 155 | } 156 | }, 157 | { 158 | "id": 80, 159 | "userid": 477, 160 | "name": "Unnamed Device", 161 | "type": "Unknown", 162 | "whencreated": "2016-04-26 18:42:55", 163 | "phonenumber": "", 164 | "tunnelable": 0, 165 | "hidden": 0, 166 | "tags": [], 167 | "links": { 168 | "cellular": [] 169 | } 170 | }, 171 | { 172 | "id": 79, 173 | "userid": 477, 174 | "name": "Unnamed Device", 175 | "type": "Unknown", 176 | "whencreated": "2016-04-26 18:42:11", 177 | "phonenumber": "", 178 | "tunnelable": 0, 179 | "hidden": 0, 180 | "tags": [], 181 | "links": { 182 | "cellular": [] 183 | } 184 | }, 185 | { 186 | "id": 78, 187 | "userid": 477, 188 | "name": "Unnamed Device", 189 | "type": "Unknown", 190 | "whencreated": "2016-04-26 18:42:08", 191 | "phonenumber": "", 192 | "tunnelable": 0, 193 | "hidden": 0, 194 | "tags": [], 195 | "links": { 196 | "cellular": [] 197 | } 198 | }, 199 | { 200 | "id": 77, 201 | "userid": 1, 202 | "name": "Unnamed Device", 203 | "type": "Unknown", 204 | "whencreated": "2016-04-18 17:49:29", 205 | "phonenumber": "", 206 | "tunnelable": 0, 207 | "hidden": 0, 208 | "tags": [], 209 | "links": { 210 | "cellular": [] 211 | } 212 | } 213 | ] 214 | } -------------------------------------------------------------------------------- /json/plan.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": [ 4 | { 5 | "id": 51, 6 | "partnerid": 1, 7 | "name": "1 MB", 8 | "description": "", 9 | "data": 1000000, 10 | "recurring": 1, 11 | "enabled": 1, 12 | "amount1": "2.34", 13 | "amount2": "3.94", 14 | "amount3": "5.89", 15 | "amount4": "7.85", 16 | "amount5": "26.52", 17 | "billingperiod": 24, 18 | "overage1": "0.20", 19 | "overage2": "0.55", 20 | "overage3": "0.98", 21 | "overage4": "1.41", 22 | "overage5": "5.48", 23 | "sms1": "0.19", 24 | "sms2": "0.30", 25 | "sms3": "0.31", 26 | "sms4": "0.46", 27 | "sms5": "0.55", 28 | "trialdays": 0, 29 | "templateid": 0, 30 | "carrierid": 1, 31 | "groupid": 0 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /json/plans.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": [ 4 | { 5 | "id": 101, 6 | "partnerid": 99, 7 | "name": "TEMP PLAN", 8 | "description": "", 9 | "data": 0, 10 | "recurring": 1, 11 | "enabled": 1, 12 | "amount1": "123.00", 13 | "amount2": "0.00", 14 | "amount3": "0.00", 15 | "amount4": "0.00", 16 | "amount5": "0.00", 17 | "billingperiod": 1, 18 | "overage1": "123.00", 19 | "overage2": "0.00", 20 | "overage3": "0.00", 21 | "overage4": "0.00", 22 | "overage5": "0.00", 23 | "sms1": "123.00", 24 | "sms2": "0.00", 25 | "sms3": "0.00", 26 | "sms4": "0.00", 27 | "sms5": "0.00", 28 | "trialdays": 0, 29 | "templateid": 0, 30 | "carrierid": 1, 31 | "groupid": 333 32 | }, 33 | { 34 | "id": 100, 35 | "partnerid": 99, 36 | "name": "TEMP PLAN", 37 | "description": "", 38 | "data": 0, 39 | "recurring": 1, 40 | "enabled": 1, 41 | "amount1": "123.00", 42 | "amount2": "0.00", 43 | "amount3": "0.00", 44 | "amount4": "0.00", 45 | "amount5": "0.00", 46 | "billingperiod": 1, 47 | "overage1": "123.00", 48 | "overage2": "0.00", 49 | "overage3": "0.00", 50 | "overage4": "0.00", 51 | "overage5": "0.00", 52 | "sms1": "123.00", 53 | "sms2": "0.00", 54 | "sms3": "0.00", 55 | "sms4": "0.00", 56 | "sms5": "0.00", 57 | "trialdays": 0, 58 | "templateid": 0, 59 | "carrierid": 1, 60 | "groupid": 543 61 | }, 62 | { 63 | "id": 80, 64 | "partnerid": 1, 65 | "name": "PAYG", 66 | "description": "", 67 | "data": 0, 68 | "recurring": 1, 69 | "enabled": 1, 70 | "amount1": "0.40", 71 | "amount2": "0.60", 72 | "amount3": "-1.00", 73 | "amount4": "-1.00", 74 | "amount5": "-1.00", 75 | "billingperiod": 1, 76 | "overage1": "0.60", 77 | "overage2": "0.85", 78 | "overage3": "-1.00", 79 | "overage4": "-1.00", 80 | "overage5": "-1.00", 81 | "sms1": "0.19", 82 | "sms2": "0.30", 83 | "sms3": "-1.00", 84 | "sms4": "-1.00", 85 | "sms5": "-1.00", 86 | "trialdays": 0, 87 | "templateid": 0, 88 | "carrierid": 2, 89 | "groupid": 0 90 | }, 91 | { 92 | "id": 79, 93 | "partnerid": 1, 94 | "name": "PAYG", 95 | "description": "", 96 | "data": 0, 97 | "recurring": 1, 98 | "enabled": 1, 99 | "amount1": "0.40", 100 | "amount2": "0.40", 101 | "amount3": "-1.00", 102 | "amount4": "-1.00", 103 | "amount5": "-1.00", 104 | "billingperiod": 1, 105 | "overage1": "0.60", 106 | "overage2": "0.85", 107 | "overage3": "-1.00", 108 | "overage4": "-1.00", 109 | "overage5": "-1.00", 110 | "sms1": "0.19", 111 | "sms2": "0.30", 112 | "sms3": "-1.00", 113 | "sms4": "-1.00", 114 | "sms5": "-1.00", 115 | "trialdays": 0, 116 | "templateid": 0, 117 | "carrierid": 3, 118 | "groupid": 0 119 | }, 120 | { 121 | "id": 78, 122 | "partnerid": 1, 123 | "name": "2 MB", 124 | "description": "", 125 | "data": 2000000, 126 | "recurring": 1, 127 | "enabled": 1, 128 | "amount1": "0.97", 129 | "amount2": "1.19", 130 | "amount3": "-1.00", 131 | "amount4": "-1.00", 132 | "amount5": "-1.00", 133 | "billingperiod": 1, 134 | "overage1": "1.00", 135 | "overage2": "1.00", 136 | "overage3": "0.00", 137 | "overage4": "0.00", 138 | "overage5": "0.00", 139 | "sms1": "0.19", 140 | "sms2": "0.19", 141 | "sms3": "-1.00", 142 | "sms4": "-1.00", 143 | "sms5": "-1.00", 144 | "trialdays": 0, 145 | "templateid": 0, 146 | "carrierid": 3, 147 | "groupid": 0 148 | }, 149 | { 150 | "id": 77, 151 | "partnerid": 1, 152 | "name": "1 MB + 30-day Free Trial", 153 | "description": "", 154 | "data": 1000000, 155 | "recurring": 1, 156 | "enabled": 1, 157 | "amount1": "0.97", 158 | "amount2": "1.19", 159 | "amount3": "-1.00", 160 | "amount4": "-1.00", 161 | "amount5": "-1.00", 162 | "billingperiod": 1, 163 | "overage1": "1.00", 164 | "overage2": "1.00", 165 | "overage3": "0.00", 166 | "overage4": "0.00", 167 | "overage5": "0.00", 168 | "sms1": "0.19", 169 | "sms2": "0.19", 170 | "sms3": "-1.00", 171 | "sms4": "-1.00", 172 | "sms5": "-1.00", 173 | "trialdays": 30, 174 | "templateid": 0, 175 | "carrierid": 3, 176 | "groupid": 0 177 | }, 178 | { 179 | "id": 75, 180 | "partnerid": 1, 181 | "name": "5 MB", 182 | "description": "", 183 | "data": 5000000, 184 | "recurring": 1, 185 | "enabled": 1, 186 | "amount1": "2.75", 187 | "amount2": "3.00", 188 | "amount3": "-1.00", 189 | "amount4": "-1.00", 190 | "amount5": "-1.00", 191 | "billingperiod": 12, 192 | "overage1": "0.00", 193 | "overage2": "0.00", 194 | "overage3": "0.00", 195 | "overage4": "0.00", 196 | "overage5": "0.00", 197 | "sms1": "0.19", 198 | "sms2": "0.19", 199 | "sms3": "-1.00", 200 | "sms4": "-1.00", 201 | "sms5": "-1.00", 202 | "trialdays": 0, 203 | "templateid": 0, 204 | "carrierid": 2, 205 | "groupid": 2 206 | }, 207 | { 208 | "id": 74, 209 | "partnerid": 1, 210 | "name": "5 MB", 211 | "description": "", 212 | "data": 5000000, 213 | "recurring": 1, 214 | "enabled": 1, 215 | "amount1": "2.98", 216 | "amount2": "3.19", 217 | "amount3": "-1.00", 218 | "amount4": "-1.00", 219 | "amount5": "-1.00", 220 | "billingperiod": 12, 221 | "overage1": "1.00", 222 | "overage2": "1.00", 223 | "overage3": "0.00", 224 | "overage4": "0.00", 225 | "overage5": "0.00", 226 | "sms1": "0.19", 227 | "sms2": "0.19", 228 | "sms3": "-1.00", 229 | "sms4": "-1.00", 230 | "sms5": "-1.00", 231 | "trialdays": 0, 232 | "templateid": 0, 233 | "carrierid": 2, 234 | "groupid": 0 235 | }, 236 | { 237 | "id": 73, 238 | "partnerid": 1, 239 | "name": "500 MB", 240 | "description": "", 241 | "data": 500000000, 242 | "recurring": 1, 243 | "enabled": 1, 244 | "amount1": "49.97", 245 | "amount2": "-1.00", 246 | "amount3": "-1.00", 247 | "amount4": "-1.00", 248 | "amount5": "-1.00", 249 | "billingperiod": 1, 250 | "overage1": "0.00", 251 | "overage2": "0.00", 252 | "overage3": "0.00", 253 | "overage4": "0.00", 254 | "overage5": "0.00", 255 | "sms1": "0.19", 256 | "sms2": "-1.00", 257 | "sms3": "-1.00", 258 | "sms4": "-1.00", 259 | "sms5": "-1.00", 260 | "trialdays": 0, 261 | "templateid": 0, 262 | "carrierid": 2, 263 | "groupid": 0 264 | }, 265 | { 266 | "id": 72, 267 | "partnerid": 1, 268 | "name": "250 MB", 269 | "description": "", 270 | "data": 250000000, 271 | "recurring": 1, 272 | "enabled": 1, 273 | "amount1": "27.98", 274 | "amount2": "-1.00", 275 | "amount3": "-1.00", 276 | "amount4": "-1.00", 277 | "amount5": "-1.00", 278 | "billingperiod": 1, 279 | "overage1": "0.00", 280 | "overage2": "0.00", 281 | "overage3": "0.00", 282 | "overage4": "0.00", 283 | "overage5": "0.00", 284 | "sms1": "0.19", 285 | "sms2": "-1.00", 286 | "sms3": "-1.00", 287 | "sms4": "-1.00", 288 | "sms5": "-1.00", 289 | "trialdays": 0, 290 | "templateid": 0, 291 | "carrierid": 2, 292 | "groupid": 0 293 | }, 294 | { 295 | "id": 71, 296 | "partnerid": 1, 297 | "name": "125 MB", 298 | "description": "", 299 | "data": 125000000, 300 | "recurring": 1, 301 | "enabled": 1, 302 | "amount1": "15.98", 303 | "amount2": "52.97", 304 | "amount3": "-1.00", 305 | "amount4": "-1.00", 306 | "amount5": "-1.00", 307 | "billingperiod": 1, 308 | "overage1": "0.00", 309 | "overage2": "0.00", 310 | "overage3": "0.00", 311 | "overage4": "0.00", 312 | "overage5": "0.00", 313 | "sms1": "0.19", 314 | "sms2": "0.19", 315 | "sms3": "-1.00", 316 | "sms4": "-1.00", 317 | "sms5": "-1.00", 318 | "trialdays": 0, 319 | "templateid": 0, 320 | "carrierid": 2, 321 | "groupid": 0 322 | }, 323 | { 324 | "id": 70, 325 | "partnerid": 1, 326 | "name": "100 MB", 327 | "description": "", 328 | "data": 100000000, 329 | "recurring": 1, 330 | "enabled": 1, 331 | "amount1": "12.49", 332 | "amount2": "42.59", 333 | "amount3": "-1.00", 334 | "amount4": "-1.00", 335 | "amount5": "-1.00", 336 | "billingperiod": 1, 337 | "overage1": "0.00", 338 | "overage2": "0.00", 339 | "overage3": "0.00", 340 | "overage4": "0.00", 341 | "overage5": "0.00", 342 | "sms1": "0.19", 343 | "sms2": "0.19", 344 | "sms3": "-1.00", 345 | "sms4": "-1.00", 346 | "sms5": "-1.00", 347 | "trialdays": 0, 348 | "templateid": 0, 349 | "carrierid": 2, 350 | "groupid": 0 351 | }, 352 | { 353 | "id": 69, 354 | "partnerid": 1, 355 | "name": "50 MB", 356 | "description": "", 357 | "data": 50000000, 358 | "recurring": 1, 359 | "enabled": 1, 360 | "amount1": "6.97", 361 | "amount2": "24.98", 362 | "amount3": "-1.00", 363 | "amount4": "-1.00", 364 | "amount5": "-1.00", 365 | "billingperiod": 1, 366 | "overage1": "0.00", 367 | "overage2": "0.00", 368 | "overage3": "0.00", 369 | "overage4": "0.00", 370 | "overage5": "0.00", 371 | "sms1": "0.19", 372 | "sms2": "0.19", 373 | "sms3": "-1.00", 374 | "sms4": "-1.00", 375 | "sms5": "-1.00", 376 | "trialdays": 0, 377 | "templateid": 0, 378 | "carrierid": 2, 379 | "groupid": 0 380 | }, 381 | { 382 | "id": 68, 383 | "partnerid": 1, 384 | "name": "30 MB", 385 | "description": "", 386 | "data": 30000000, 387 | "recurring": 1, 388 | "enabled": 1, 389 | "amount1": "5.49", 390 | "amount2": "14.97", 391 | "amount3": "-1.00", 392 | "amount4": "-1.00", 393 | "amount5": "-1.00", 394 | "billingperiod": 1, 395 | "overage1": "0.00", 396 | "overage2": "0.00", 397 | "overage3": "0.00", 398 | "overage4": "0.00", 399 | "overage5": "0.00", 400 | "sms1": "0.19", 401 | "sms2": "0.19", 402 | "sms3": "-1.00", 403 | "sms4": "-1.00", 404 | "sms5": "-1.00", 405 | "trialdays": 0, 406 | "templateid": 0, 407 | "carrierid": 2, 408 | "groupid": 0 409 | }, 410 | { 411 | "id": 67, 412 | "partnerid": 1, 413 | "name": "20 MB", 414 | "description": "", 415 | "data": 20000000, 416 | "recurring": 1, 417 | "enabled": 1, 418 | "amount1": "4.95", 419 | "amount2": "10.49", 420 | "amount3": "-1.00", 421 | "amount4": "-1.00", 422 | "amount5": "-1.00", 423 | "billingperiod": 1, 424 | "overage1": "0.00", 425 | "overage2": "0.00", 426 | "overage3": "0.00", 427 | "overage4": "0.00", 428 | "overage5": "0.00", 429 | "sms1": "0.19", 430 | "sms2": "0.19", 431 | "sms3": "-1.00", 432 | "sms4": "-1.00", 433 | "sms5": "-1.00", 434 | "trialdays": 0, 435 | "templateid": 0, 436 | "carrierid": 2, 437 | "groupid": 0 438 | }, 439 | { 440 | "id": 66, 441 | "partnerid": 1, 442 | "name": "10 MB", 443 | "description": "", 444 | "data": 10000000, 445 | "recurring": 1, 446 | "enabled": 1, 447 | "amount1": "3.95", 448 | "amount2": "5.98", 449 | "amount3": "-1.00", 450 | "amount4": "-1.00", 451 | "amount5": "-1.00", 452 | "billingperiod": 1, 453 | "overage1": "0.00", 454 | "overage2": "0.00", 455 | "overage3": "0.00", 456 | "overage4": "0.00", 457 | "overage5": "0.00", 458 | "sms1": "0.19", 459 | "sms2": "0.19", 460 | "sms3": "-1.00", 461 | "sms4": "-1.00", 462 | "sms5": "-1.00", 463 | "trialdays": 0, 464 | "templateid": 0, 465 | "carrierid": 2, 466 | "groupid": 0 467 | }, 468 | { 469 | "id": 65, 470 | "partnerid": 1, 471 | "name": "5 MB", 472 | "description": "", 473 | "data": 5000000, 474 | "recurring": 1, 475 | "enabled": 1, 476 | "amount1": "2.98", 477 | "amount2": "3.19", 478 | "amount3": "-1.00", 479 | "amount4": "-1.00", 480 | "amount5": "-1.00", 481 | "billingperiod": 1, 482 | "overage1": "0.00", 483 | "overage2": "0.00", 484 | "overage3": "0.00", 485 | "overage4": "0.00", 486 | "overage5": "0.00", 487 | "sms1": "0.19", 488 | "sms2": "0.19", 489 | "sms3": "-1.00", 490 | "sms4": "-1.00", 491 | "sms5": "-1.00", 492 | "trialdays": 0, 493 | "templateid": 0, 494 | "carrierid": 2, 495 | "groupid": 0 496 | }, 497 | { 498 | "id": 64, 499 | "partnerid": 1, 500 | "name": "3 MB", 501 | "description": "", 502 | "data": 3000000, 503 | "recurring": 1, 504 | "enabled": 1, 505 | "amount1": "1.97", 506 | "amount2": "2.19", 507 | "amount3": "-1.00", 508 | "amount4": "-1.00", 509 | "amount5": "-1.00", 510 | "billingperiod": 1, 511 | "overage1": "0.00", 512 | "overage2": "0.00", 513 | "overage3": "0.00", 514 | "overage4": "0.00", 515 | "overage5": "0.00", 516 | "sms1": "0.19", 517 | "sms2": "0.19", 518 | "sms3": "-1.00", 519 | "sms4": "-1.00", 520 | "sms5": "-1.00", 521 | "trialdays": 0, 522 | "templateid": 0, 523 | "carrierid": 2, 524 | "groupid": 0 525 | }, 526 | { 527 | "id": 62, 528 | "partnerid": 1, 529 | "name": "1 MB + 30-day Free Trial", 530 | "description": "", 531 | "data": 1000000, 532 | "recurring": 1, 533 | "enabled": 1, 534 | "amount1": "0.97", 535 | "amount2": "1.19", 536 | "amount3": "-1.00", 537 | "amount4": "-1.00", 538 | "amount5": "-1.00", 539 | "billingperiod": 1, 540 | "overage1": "0.00", 541 | "overage2": "0.00", 542 | "overage3": "0.00", 543 | "overage4": "0.00", 544 | "overage5": "0.00", 545 | "sms1": "0.19", 546 | "sms2": "0.19", 547 | "sms3": "-1.00", 548 | "sms4": "-1.00", 549 | "sms5": "-1.00", 550 | "trialdays": 30, 551 | "templateid": 0, 552 | "carrierid": 2, 553 | "groupid": 0 554 | }, 555 | { 556 | "id": 61, 557 | "partnerid": 1, 558 | "name": "500 KB", 559 | "description": "", 560 | "data": 500000, 561 | "recurring": 1, 562 | "enabled": 1, 563 | "amount1": "0.55", 564 | "amount2": "-1.00", 565 | "amount3": "-1.00", 566 | "amount4": "-1.00", 567 | "amount5": "-1.00", 568 | "billingperiod": 1, 569 | "overage1": "0.00", 570 | "overage2": "0.00", 571 | "overage3": "0.00", 572 | "overage4": "0.00", 573 | "overage5": "0.00", 574 | "sms1": "0.19", 575 | "sms2": "-1.00", 576 | "sms3": "-1.00", 577 | "sms4": "-1.00", 578 | "sms5": "-1.00", 579 | "trialdays": 0, 580 | "templateid": 0, 581 | "carrierid": 2, 582 | "groupid": 0 583 | }, 584 | { 585 | "id": 57, 586 | "partnerid": 1, 587 | "name": "10 MB", 588 | "description": "", 589 | "data": 10000000, 590 | "recurring": 1, 591 | "enabled": 1, 592 | "amount1": "7.07", 593 | "amount2": "23.00", 594 | "amount3": "42.52", 595 | "amount4": "62.11", 596 | "amount5": "248.88", 597 | "billingperiod": 24, 598 | "overage1": "0.20", 599 | "overage2": "0.55", 600 | "overage3": "0.98", 601 | "overage4": "1.41", 602 | "overage5": "5.48", 603 | "sms1": "0.19", 604 | "sms2": "0.30", 605 | "sms3": "0.31", 606 | "sms4": "0.46", 607 | "sms5": "0.55", 608 | "trialdays": 0, 609 | "templateid": 0, 610 | "carrierid": 1, 611 | "groupid": 0 612 | }, 613 | { 614 | "id": 55, 615 | "partnerid": 1, 616 | "name": "5 MB", 617 | "description": "", 618 | "data": 5000000, 619 | "recurring": 1, 620 | "enabled": 1, 621 | "amount1": "4.45", 622 | "amount2": "12.41", 623 | "amount3": "22.17", 624 | "amount4": "31.96", 625 | "amount5": "125.35", 626 | "billingperiod": 24, 627 | "overage1": "0.20", 628 | "overage2": "0.55", 629 | "overage3": "0.98", 630 | "overage4": "1.41", 631 | "overage5": "5.48", 632 | "sms1": "0.19", 633 | "sms2": "0.30", 634 | "sms3": "0.31", 635 | "sms4": "0.46", 636 | "sms5": "0.55", 637 | "trialdays": 0, 638 | "templateid": 0, 639 | "carrierid": 1, 640 | "groupid": 0 641 | }, 642 | { 643 | "id": 52, 644 | "partnerid": 1, 645 | "name": "3 MB", 646 | "description": "", 647 | "data": 3000000, 648 | "recurring": 1, 649 | "enabled": 1, 650 | "amount1": "3.40", 651 | "amount2": "8.17", 652 | "amount3": "14.03", 653 | "amount4": "19.91", 654 | "amount5": "75.94", 655 | "billingperiod": 24, 656 | "overage1": "0.20", 657 | "overage2": "0.55", 658 | "overage3": "0.98", 659 | "overage4": "1.41", 660 | "overage5": "5.48", 661 | "sms1": "0.19", 662 | "sms2": "0.30", 663 | "sms3": "0.31", 664 | "sms4": "0.46", 665 | "sms5": "0.55", 666 | "trialdays": 0, 667 | "templateid": 0, 668 | "carrierid": 1, 669 | "groupid": 0 670 | }, 671 | { 672 | "id": 51, 673 | "partnerid": 1, 674 | "name": "1 MB", 675 | "description": "", 676 | "data": 1000000, 677 | "recurring": 1, 678 | "enabled": 1, 679 | "amount1": "2.34", 680 | "amount2": "3.94", 681 | "amount3": "5.89", 682 | "amount4": "7.85", 683 | "amount5": "26.52", 684 | "billingperiod": 24, 685 | "overage1": "0.20", 686 | "overage2": "0.55", 687 | "overage3": "0.98", 688 | "overage4": "1.41", 689 | "overage5": "5.48", 690 | "sms1": "0.19", 691 | "sms2": "0.30", 692 | "sms3": "0.31", 693 | "sms4": "0.46", 694 | "sms5": "0.55", 695 | "trialdays": 0, 696 | "templateid": 0, 697 | "carrierid": 1, 698 | "groupid": 0 699 | }, 700 | { 701 | "id": 49, 702 | "partnerid": 1, 703 | "name": "10 MB", 704 | "description": "", 705 | "data": 10000000, 706 | "recurring": 1, 707 | "enabled": 1, 708 | "amount1": "8.08", 709 | "amount2": "26.28", 710 | "amount3": "48.59", 711 | "amount4": "70.98", 712 | "amount5": "284.44", 713 | "billingperiod": 12, 714 | "overage1": "0.20", 715 | "overage2": "0.55", 716 | "overage3": "0.98", 717 | "overage4": "1.41", 718 | "overage5": "5.48", 719 | "sms1": "0.19", 720 | "sms2": "0.30", 721 | "sms3": "0.31", 722 | "sms4": "0.46", 723 | "sms5": "0.55", 724 | "trialdays": 0, 725 | "templateid": 0, 726 | "carrierid": 1, 727 | "groupid": 0 728 | } 729 | ] 730 | } 731 | -------------------------------------------------------------------------------- /json/product.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": { 4 | "id": 1, 5 | "sku": "SIM", 6 | "name": "SIM Card", 7 | "description": "The Hologram Global SIM Card. Comes in a variety of sizes for any application. (Pick your data plan when you go to activate the SIM.)", 8 | "price": "5.00", 9 | "imageurl": "https://dashboard.hologram.io/img/sim_card.jpg", 10 | "invoice_description": "Global SIM Card", 11 | "preorder_details": "", 12 | "options": [ 13 | { 14 | "id": 17, 15 | "appendsku": "N2-2FF3FF4FF", 16 | "pricechange": "0.00", 17 | "description": "Combo Mini/Micro/Nano SIM" 18 | } 19 | ], 20 | "categories": [ 21 | "cellular" 22 | ] 23 | } 24 | } -------------------------------------------------------------------------------- /json/product_categories.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": [ 4 | { 5 | "category": "accessories", 6 | "productids": [ 7 | 15, 8 | 19, 9 | 11, 10 | 10, 11 | 9, 12 | 8, 13 | 7, 14 | 23 15 | ] 16 | }, 17 | { 18 | "category": "cellular", 19 | "productids": [ 20 | 20, 21 | 21, 22 | 18, 23 | 17, 24 | 1, 25 | 24, 26 | 6, 27 | 4, 28 | 3 29 | ] 30 | }, 31 | { 32 | "category": "devkits", 33 | "productids": [ 34 | 16, 35 | 14, 36 | 12, 37 | 13 38 | ] 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /json/product_options.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": [ 4 | { 5 | "productid": 0, 6 | "appendsku": "N2-2FF3FF", 7 | "pricechange": "0.00", 8 | "description": "Combo Mini/Micro SIM", 9 | "invoice_description": "Mini/Micro SIM" 10 | }, 11 | { 12 | "productid": 2, 13 | "appendsku": "5DASH", 14 | "pricechange": "0.00", 15 | "description": "5 Dashes", 16 | "invoice_description": "5 Dashes" 17 | }, 18 | { 19 | "productid": 2, 20 | "appendsku": "4DASHPRO", 21 | "pricechange": "0.00", 22 | "description": "4 Dash Pros", 23 | "invoice_description": "4 Dash Pros" 24 | }, 25 | { 26 | "productid": 0, 27 | "appendsku": "E303", 28 | "pricechange": "0.00", 29 | "description": "Europe/Asia 2100MHz 3G", 30 | "invoice_description": "EU/Asia Version" 31 | }, 32 | { 33 | "productid": 6, 34 | "appendsku": "E303US", 35 | "pricechange": "0.00", 36 | "description": "North America 850/1900 MHz 3G", 37 | "invoice_description": "North America Version" 38 | }, 39 | { 40 | "productid": 12, 41 | "appendsku": "ASSET260", 42 | "pricechange": "0.00", 43 | "description": "Dash NA/SA 850/1900 3G (SU260)", 44 | "invoice_description": "Dash (SU260)" 45 | }, 46 | { 47 | "productid": 12, 48 | "appendsku": "ASSETPRO", 49 | "pricechange": "10.00", 50 | "description": "Dash Pro", 51 | "invoice_description": "Dash Pro" 52 | }, 53 | { 54 | "productid": 13, 55 | "appendsku": "SENSOR260", 56 | "pricechange": "0.00", 57 | "description": "Dash NA/SA 850/1900 3G (SU260)", 58 | "invoice_description": "Dash (SU260)" 59 | }, 60 | { 61 | "productid": 13, 62 | "appendsku": "SENSOR270", 63 | "pricechange": "0.00", 64 | "description": "Dash EU/AS 2100MHz 3G (SU2270)", 65 | "invoice_description": "Dash Pro (SU270)" 66 | }, 67 | { 68 | "productid": 14, 69 | "appendsku": "SOLAR260", 70 | "pricechange": "0.00", 71 | "description": "Dash NA/SA 850/1900 3G (SU260)", 72 | "invoice_description": "Dash (SU260)" 73 | }, 74 | { 75 | "productid": 14, 76 | "appendsku": "SOLARPRO", 77 | "pricechange": "10.00", 78 | "description": "Dash Pro", 79 | "invoice_description": "Dash Pro" 80 | }, 81 | { 82 | "productid": 15, 83 | "appendsku": "XS", 84 | "pricechange": "0.00", 85 | "description": "XS", 86 | "invoice_description": "XS" 87 | }, 88 | { 89 | "productid": 15, 90 | "appendsku": "S", 91 | "pricechange": "0.00", 92 | "description": "S", 93 | "invoice_description": "S" 94 | }, 95 | { 96 | "productid": 15, 97 | "appendsku": "M", 98 | "pricechange": "0.00", 99 | "description": "M", 100 | "invoice_description": "M" 101 | }, 102 | { 103 | "productid": 15, 104 | "appendsku": "L", 105 | "pricechange": "0.00", 106 | "description": "L", 107 | "invoice_description": "L" 108 | }, 109 | { 110 | "productid": 15, 111 | "appendsku": "XL", 112 | "pricechange": "0.00", 113 | "description": "XL", 114 | "invoice_description": "XL" 115 | }, 116 | { 117 | "productid": 1, 118 | "appendsku": "N2-2FF3FF4FF", 119 | "pricechange": "0.00", 120 | "description": "Combo Mini/Micro/Nano SIM", 121 | "invoice_description": "Mini/Micro/Nano SIM" 122 | }, 123 | { 124 | "productid": 0, 125 | "appendsku": "3FF", 126 | "pricechange": "0.00", 127 | "description": "Combo Mini/Micro SIMs", 128 | "invoice_description": "Mini/Micro SIMs" 129 | }, 130 | { 131 | "productid": 17, 132 | "appendsku": "4FF", 133 | "pricechange": "0.00", 134 | "description": "Combo Mini/Micro/Nano SIMs", 135 | "invoice_description": "Mini/Micro/Nano SIMs" 136 | }, 137 | { 138 | "productid": 3, 139 | "appendsku": "DASH270", 140 | "pricechange": "0.00", 141 | "description": "Europe/Asia 2100MHz 3G (SU270)", 142 | "invoice_description": "EU/Asia (SU270)" 143 | }, 144 | { 145 | "productid": 3, 146 | "appendsku": "DASH260", 147 | "pricechange": "0.00", 148 | "description": "Americas 850/1900 MHz 3G (SU260)", 149 | "invoice_description": "Americas (SU260)" 150 | }, 151 | { 152 | "productid": 13, 153 | "appendsku": "SENSORPRO", 154 | "pricechange": "10.00", 155 | "description": "Dash Pro (LU200)", 156 | "invoice_description": "Dash Pro (LU200)" 157 | }, 158 | { 159 | "productid": 14, 160 | "appendsku": "SOLAR270", 161 | "pricechange": "0.00", 162 | "description": "Dash EU/AS 2100MHz 3G (SU270)", 163 | "invoice_description": "Dash (SU270)" 164 | }, 165 | { 166 | "productid": 12, 167 | "appendsku": "ASSET270", 168 | "pricechange": "0.00", 169 | "description": "Dash EU/AS 2100MHz 3G (SU270)", 170 | "invoice_description": "Dash (SU270)" 171 | } 172 | ] 173 | } -------------------------------------------------------------------------------- /json/products.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": [ 4 | { 5 | "id": 1, 6 | "sku": "SIM", 7 | "name": "SIM Card", 8 | "description": "The Hologram Global SIM Card. Comes in a variety of sizes for any application. (Pick your data plan when you go to activate the SIM.)", 9 | "price": "5.00", 10 | "imageurl": "https://dashboard.hologram.io/img/sim_card.jpg", 11 | "invoice_description": "Global SIM Card", 12 | "preorder_details": "", 13 | "options": [ 14 | { 15 | "id": 17, 16 | "appendsku": "N2-2FF3FF4FF", 17 | "pricechange": "0.00", 18 | "description": "Combo Mini/Micro/Nano SIM" 19 | } 20 | ], 21 | "categories": [ 22 | "cellular" 23 | ] 24 | }, 25 | { 26 | "id": 3, 27 | "sku": "RE", 28 | "name": "Dash", 29 | "description": "*SHIPS IN TWO WEEKS* A tiny cellular development kit; pairs perfectly with Hologram Cloud and SIM. Order a Hologram Dash for your next cellular project! SIM included.", 30 | "price": "59.00", 31 | "imageurl": "https://dashboard.hologram.io/img/dash.jpg", 32 | "invoice_description": "Konekt Dash dev kit", 33 | "preorder_details": "", 34 | "options": [ 35 | { 36 | "id": 22, 37 | "appendsku": "DASH260", 38 | "pricechange": "0.00", 39 | "description": "Americas 850/1900 MHz 3G (SU260)" 40 | }, 41 | { 42 | "id": 21, 43 | "appendsku": "DASH270", 44 | "pricechange": "0.00", 45 | "description": "Europe/Asia 2100MHz 3G (SU270)" 46 | } 47 | ], 48 | "categories": [ 49 | "cellular" 50 | ] 51 | }, 52 | { 53 | "id": 4, 54 | "sku": "RE-DASHPRO", 55 | "name": "Dash Pro", 56 | "description": "Heavy-duty features like military grade end-to-end SSL encryption and world-wide cellular certification. SIM included.", 57 | "price": "69.00", 58 | "imageurl": "https://dashboard.hologram.io/img/dash_pro.jpg", 59 | "invoice_description": "Konekt Dash Pro dev kit", 60 | "preorder_details": "", 61 | "options": [], 62 | "categories": [ 63 | "cellular" 64 | ] 65 | }, 66 | { 67 | "id": 6, 68 | "sku": "HUA", 69 | "name": "Huawei E303 Cellular USB Modem", 70 | "description": "*EU/Asia out of stock* These unlocked 3G cellular modems are great for doing a quick cellular test on your laptop or even to hook up your Raspberry Pi or BeagleBone. Accepts a mini SIM card. (See tutorials on our blog)", 71 | "price": "28.00", 72 | "imageurl": "https://dashboard.hologram.io/img/huawei-e303.jpg", 73 | "invoice_description": "Huawei E303 Cellular Modem", 74 | "preorder_details": "", 75 | "options": [ 76 | { 77 | "id": 5, 78 | "appendsku": "E303US", 79 | "pricechange": "0.00", 80 | "description": "North America 850/1900 MHz 3G" 81 | } 82 | ], 83 | "categories": [ 84 | "cellular" 85 | ] 86 | }, 87 | { 88 | "id": 7, 89 | "sku": "BAT-LIPO2000", 90 | "name": "Battery for Dash and Dash Pro", 91 | "description": "Grab one of these 3.7v 2000 mAh LiPo batteries to run your Dash completely free of wall outlets or USBs", 92 | "price": "10.00", 93 | "imageurl": "https://dashboard.hologram.io/img/battery.jpg", 94 | "invoice_description": "Battery", 95 | "preorder_details": "", 96 | "options": [], 97 | "categories": [ 98 | "accessories" 99 | ] 100 | }, 101 | { 102 | "id": 8, 103 | "sku": "ANT-DUCK", 104 | "name": "Duck Antenna", 105 | "description": "Improve the range of your Dash or Dash Pro with this Duck Antenna", 106 | "price": "15.00", 107 | "imageurl": "https://dashboard.hologram.io/img/duck_antenna.jpg", 108 | "invoice_description": "Duck Antenna", 109 | "preorder_details": "", 110 | "options": [], 111 | "categories": [ 112 | "accessories" 113 | ] 114 | }, 115 | { 116 | "id": 9, 117 | "sku": "SHLDSHLD-V1", 118 | "name": "Shield Shield", 119 | "description": "The Shield Shield converts the footprint and pins of your Dash or Dash Pro into that of an Arduino, allowing for use of existing Arduino shields and accessories.", 120 | "price": "20.00", 121 | "imageurl": "https://dashboard.hologram.io/img/shield_shield.jpg", 122 | "invoice_description": "Shield Shield", 123 | "preorder_details": "", 124 | "options": [], 125 | "categories": [ 126 | "accessories" 127 | ] 128 | }, 129 | { 130 | "id": 10, 131 | "sku": "MAGRELAY-V1", 132 | "name": "Magnetic Relay Shield", 133 | "description": "Control any normal outlet or high voltage product from anywhere.", 134 | "price": "40.00", 135 | "imageurl": "https://dashboard.hologram.io/img/relay_shield.jpg", 136 | "invoice_description": "Magnetic Relay Shield", 137 | "preorder_details": "", 138 | "options": [], 139 | "categories": [ 140 | "accessories" 141 | ] 142 | }, 143 | { 144 | "id": 12, 145 | "sku": "RE", 146 | "name": "Dash Asset Tracker Kit", 147 | "description": "*SHIPS IN TWO WEEKS* Use this combination of GPS shield and Dash or Dash Pro build your very own Asset Tracker", 148 | "price": "119.00", 149 | "imageurl": "https://dashboard.hologram.io/img/asset_tracker_kit.jpg", 150 | "invoice_description": "Asset Tracker Kit", 151 | "preorder_details": "", 152 | "options": [ 153 | { 154 | "id": 25, 155 | "appendsku": "ASSET270", 156 | "pricechange": "0.00", 157 | "description": "Dash EU/AS 2100MHz 3G (SU270)" 158 | }, 159 | { 160 | "id": 6, 161 | "appendsku": "ASSET260", 162 | "pricechange": "0.00", 163 | "description": "Dash NA/SA 850/1900 3G (SU260)" 164 | }, 165 | { 166 | "id": 7, 167 | "appendsku": "ASSETPRO", 168 | "pricechange": "10.00", 169 | "description": "Dash Pro" 170 | } 171 | ], 172 | "categories": [ 173 | "devkits" 174 | ] 175 | }, 176 | { 177 | "id": 13, 178 | "sku": "RE", 179 | "name": "Dash Sensor Kit", 180 | "description": "Includes all the sensors you could ever want. Temperature, Motion, Air Quality, Sound, Acceleration, Vibration, this one has it all! Includes a Hologram Dash, all of the sensors, and a Hologram SIM.", 181 | "price": "139.00", 182 | "imageurl": "https://dashboard.hologram.io/img/sensor_kit.jpg", 183 | "invoice_description": "Sensor Kit", 184 | "preorder_details": "", 185 | "options": [ 186 | { 187 | "id": 9, 188 | "appendsku": "SENSOR270", 189 | "pricechange": "0.00", 190 | "description": "Dash EU/AS 2100MHz 3G (SU2270)" 191 | }, 192 | { 193 | "id": 8, 194 | "appendsku": "SENSOR260", 195 | "pricechange": "0.00", 196 | "description": "Dash NA/SA 850/1900 3G (SU260)" 197 | }, 198 | { 199 | "id": 23, 200 | "appendsku": "SENSORPRO", 201 | "pricechange": "10.00", 202 | "description": "Dash Pro (LU200)" 203 | } 204 | ], 205 | "categories": [ 206 | "devkits" 207 | ] 208 | }, 209 | { 210 | "id": 23, 211 | "sku": "USBYCABLE", 212 | "name": "USB Y-Cable", 213 | "description": "Some computers don't provide enough power to their USB ports to power the Dash. Use this cable to supplement it if you're having trouble. (2 USB A Male to 1 USB Micro Male)", 214 | "price": "5.00", 215 | "imageurl": "https://dashboard.hologram.io/img/y_cable.jpg", 216 | "invoice_description": "USB Y-Cable", 217 | "preorder_details": "", 218 | "options": [], 219 | "categories": [ 220 | "accessories" 221 | ] 222 | } 223 | ] 224 | } --------------------------------------------------------------------------------