Skip to content

Commit 8fa7bfa

Browse files
authored
Remaining dashboard endpoints (#26)
1 parent c9da4cb commit 8fa7bfa

18 files changed

+475
-2
lines changed

accounting_client.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ type AccountingClient interface {
1212
GetEntitlements(ctx context.Context) (*GetEntitlementsOutput, error)
1313
// HasEntitlement will return true if you have the provided entitlement is
1414
HasEntitlement(ctx context.Context, entitlement string) (bool, error)
15+
// GetLicense returns a truncated view of your license information
16+
GetLicense(ctx context.Context) (*GetLicenseOutput, error)
17+
// ListAccountingUsers returns account user information
18+
ListAccountingUsers(ctx context.Context, input *ListAccountingUsersInput) (*ListAccountingUsersOutput, error)
1519
}
1620

1721
type standardAccountingClient struct {
@@ -53,3 +57,39 @@ func (c *standardAccountingClient) HasEntitlement(ctx context.Context, entitleme
5357
}
5458
return false, nil
5559
}
60+
func (c *standardAccountingClient) GetLicense(ctx context.Context) (*GetLicenseOutput, error) {
61+
var out model.License
62+
url := "/api/license"
63+
_, err := c.baseClient.requestor.Get(ctx, url, &out)
64+
if err != nil {
65+
return nil, err
66+
}
67+
68+
return &GetLicenseOutput{
69+
License: out,
70+
}, nil
71+
}
72+
73+
func (c *standardAccountingClient) ListAccountingUsers(ctx context.Context, input *ListAccountingUsersInput) (*ListAccountingUsersOutput, error) {
74+
input.Paging = input.Paging.withDefaults()
75+
76+
var items []model.AccountingUser
77+
url := "/api/accounting/users"
78+
_, links, err := c.baseClient.requestor.List(ctx, url, input.Paging, &items)
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
// decide if we have a next page (the next link is not always accurate?)
84+
var nextPage *ListAccountingUsersInput
85+
if _, hasNextLink := links["next"]; len(items) == input.Paging.PerPage && hasNextLink {
86+
nextPage = &ListAccountingUsersInput{
87+
Paging: input.Paging.Next(),
88+
}
89+
}
90+
91+
return &ListAccountingUsersOutput{
92+
Users: items,
93+
NextPage: nextPage,
94+
}, nil
95+
}

accounting_client_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,41 @@ func TestHasEntitlementHTTPError(t *testing.T) {
5858
}
5959
}
6060

61+
func TestGetLicenseHTTPError(t *testing.T) {
62+
serv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
63+
w.WriteHeader(500)
64+
}))
65+
defer serv.Close()
66+
67+
client := NewClient(serv.URL)
68+
_, err := client.Accounting().GetLicense(context.TODO())
69+
if err == nil {
70+
t.Errorf("Expected error")
71+
}
72+
}
73+
74+
func TestGetLicense(t *testing.T) {
75+
serv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
76+
if r.Method != "GET" {
77+
t.Errorf("expected method to be GET, got %s", r.Method)
78+
}
79+
if r.RequestURI != "/api/license" {
80+
t.Errorf("get url not expected: %s", r.RequestURI)
81+
}
82+
w.Write([]byte(`{"companyName": "cn"}`))
83+
}))
84+
defer serv.Close()
85+
86+
client := NewClient(serv.URL)
87+
out, err := client.Accounting().GetLicense(context.TODO())
88+
if err != nil {
89+
t.Errorf("err not nil: %v", err)
90+
}
91+
if out.License.CompanyName != "cn" {
92+
t.Errorf("Expected entitlement one, got %s", out.License.CompanyName)
93+
}
94+
}
95+
6196
func TestHasEntitlement(t *testing.T) {
6297
serv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
6398
if r.Method != "GET" {
@@ -88,3 +123,43 @@ func TestHasEntitlement(t *testing.T) {
88123
t.Errorf("Expected to have entitlment")
89124
}
90125
}
126+
127+
func TestListAccountingUsersHTTPError(t *testing.T) {
128+
serv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
129+
w.WriteHeader(500)
130+
}))
131+
defer serv.Close()
132+
client := NewClient(serv.URL)
133+
_, err := client.Accounting().ListAccountingUsers(context.TODO(), (&ListAccountingUsersInput{}).WithPaging(2, 3))
134+
if err == nil {
135+
t.Errorf("Expected error")
136+
}
137+
}
138+
139+
func TestListAccountingUsers(t *testing.T) {
140+
serv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
141+
if r.Method != "GET" {
142+
t.Errorf("expected method to be GET, got %s", r.Method)
143+
}
144+
if r.RequestURI != "/api/accounting/users?page=7&per-page=2" {
145+
t.Errorf("get url not expected: %s", r.RequestURI)
146+
}
147+
w.Header().Set("Link", `<https://example>; rel="next"`)
148+
w.Write([]byte(`[{"email": "jsonID"},{"email": "jsonID2"}]`))
149+
}))
150+
defer serv.Close()
151+
client := NewClient(serv.URL)
152+
out, err := client.Accounting().ListAccountingUsers(context.TODO(), (&ListAccountingUsersInput{}).WithPaging(2, 7))
153+
if err != nil {
154+
t.Errorf("err not nil: %v", err)
155+
}
156+
if out.Users[0].Email != "jsonID" {
157+
t.Errorf("response not parsed")
158+
}
159+
if out.NextPage == nil {
160+
t.Errorf("expected NextPage to have a value")
161+
}
162+
if out.NextPage.Paging.Page != 8 {
163+
t.Errorf("expected NextPage to be next")
164+
}
165+
}

accounting_params.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,51 @@ import "github.com/modzy/sdk-go/model"
66
type GetEntitlementsOutput struct {
77
Entitlements []model.Entitlement `json:"entitlements"`
88
}
9+
10+
type ListAccountingUsersInput struct {
11+
Paging PagingInput
12+
}
13+
14+
// ListAccountingUsersFilterField are known field names that can be used when filtering the jobs history
15+
type ListAccountingUsersFilterField string
16+
17+
const (
18+
ListAccountingUsersFilterFieldFirstName ListAccountingUsersFilterField = "firstName"
19+
ListAccountingUsersFilterFieldLastName ListAccountingUsersFilterField = "lastName"
20+
ListAccountingUsersFilterFieldEmail ListAccountingUsersFilterField = "email"
21+
ListAccountingUsersFilterFieldSearch ListAccountingUsersFilterField = "search"
22+
ListAccountingUsersFilterFieldStatus ListAccountingUsersFilterField = "status"
23+
ListAccountingUsersFilterFieldAccessKey ListAccountingUsersFilterField = "accessKey"
24+
ListAccountingUsersFilterFieldStartDate ListAccountingUsersFilterField = "startDate"
25+
ListAccountingUsersFilterFieldEndDate ListAccountingUsersFilterField = "endDate"
26+
ListAccountingUsersFilterFieldSearchDate ListAccountingUsersFilterField = "searchDate"
27+
)
28+
29+
func (i *ListAccountingUsersInput) WithPaging(perPage int, page int) *ListAccountingUsersInput {
30+
i.Paging = NewPaging(perPage, page)
31+
return i
32+
}
33+
34+
func (i *ListAccountingUsersInput) WithFilter(field ListAccountingUsersFilterField, value string) *ListAccountingUsersInput {
35+
i.Paging = i.Paging.WithFilterAnd(string(field), value)
36+
return i
37+
}
38+
39+
func (i *ListAccountingUsersInput) WithFilterAnd(field ListAccountingUsersFilterField, values ...string) *ListAccountingUsersInput {
40+
i.Paging = i.Paging.WithFilterAnd(string(field), values...)
41+
return i
42+
}
43+
44+
func (i *ListAccountingUsersInput) WithFilterOr(field ListAccountingUsersFilterField, values ...string) *ListAccountingUsersInput {
45+
i.Paging = i.Paging.WithFilterOr(string(field), values...)
46+
return i
47+
}
48+
49+
type ListAccountingUsersOutput struct {
50+
Users []model.AccountingUser `json:"users"`
51+
NextPage *ListAccountingUsersInput `json:"nextPage"`
52+
}
53+
54+
type GetLicenseOutput struct {
55+
License model.License `json:"license"`
56+
}

accounting_params_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package modzy
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestListAccountingUsersInputWithPaging(t *testing.T) {
9+
i := &ListAccountingUsersInput{}
10+
i.WithPaging(4, 5)
11+
12+
if i.Paging.PerPage != 4 {
13+
t.Errorf("expected perPage to be 4, got %d", i.Paging.PerPage)
14+
}
15+
if i.Paging.Page != 5 {
16+
t.Errorf("expected page to be 5, got %d", i.Paging.Page)
17+
}
18+
}
19+
20+
func TestListAccountingUsersInputWithFilter(t *testing.T) {
21+
i := &ListAccountingUsersInput{}
22+
i.WithFilter(ListAccountingUsersFilterFieldAccessKey, "a")
23+
24+
if i.Paging.Filters[0].Field != "accessKey" {
25+
t.Errorf("expected filter field to be accessKey, got %s", i.Paging.Filters[0].Field)
26+
}
27+
if i.Paging.Filters[0].Type != "AND" {
28+
t.Errorf("expected filter type to be AND, got %s", i.Paging.Filters[0].Type)
29+
}
30+
if strings.Join(i.Paging.Filters[0].Values, ",") != "a" {
31+
t.Errorf("expected filter values to be [a], got %+v", i.Paging.Filters[0].Values)
32+
}
33+
}
34+
35+
func TestListAccountingUsersInputWithFilterAnd(t *testing.T) {
36+
i := &ListAccountingUsersInput{}
37+
i.WithFilterAnd(ListAccountingUsersFilterFieldAccessKey, "a", "b")
38+
39+
if i.Paging.Filters[0].Field != "accessKey" {
40+
t.Errorf("expected filter field to be accessKey, got %s", i.Paging.Filters[0].Field)
41+
}
42+
if i.Paging.Filters[0].Type != "AND" {
43+
t.Errorf("expected filter type to be AND, got %s", i.Paging.Filters[0].Type)
44+
}
45+
if strings.Join(i.Paging.Filters[0].Values, ",") != "a,b" {
46+
t.Errorf("expected filter values to be [a, b], got %+v", i.Paging.Filters[0].Values)
47+
}
48+
}
49+
50+
func TestListAccountingUsersInputWithFilterOr(t *testing.T) {
51+
i := &ListAccountingUsersInput{}
52+
i.WithFilterOr(ListAccountingUsersFilterFieldAccessKey, "c", "d")
53+
54+
if i.Paging.Filters[0].Field != "accessKey" {
55+
t.Errorf("expected filter field to be accessKey, got %s", i.Paging.Filters[0].Field)
56+
}
57+
if i.Paging.Filters[0].Type != "OR" {
58+
t.Errorf("expected filter type to be OR, got %s", i.Paging.Filters[0].Type)
59+
}
60+
if strings.Join(i.Paging.Filters[0].Values, ",") != "c,d" {
61+
t.Errorf("expected filter values to be [c, d], got %+v", i.Paging.Filters[0].Values)
62+
}
63+
}

client.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@ type Client interface {
2222
Models() ModelsClient
2323
// Dashboard returns a client for access to dashboard API functions
2424
Dashboard() DashboardClient
25+
// Resources returns a client for access to resource information
26+
Resources() ResourcesClient
2527
}
2628

2729
type standardClient struct {
2830
accountingClient *standardAccountingClient
2931
jobsClient *standardJobsClient
3032
modelsClient *standardModelsClient
3133
dashboardClient *standardDashboardClient
34+
resourcesClient *standardResourcesClient
3235
requestor *requestor
3336
}
3437

@@ -67,6 +70,9 @@ func NewClient(baseURL string, opts ...ClientOption) Client {
6770
client.dashboardClient = &standardDashboardClient{
6871
baseClient: client,
6972
}
73+
client.resourcesClient = &standardResourcesClient{
74+
baseClient: client,
75+
}
7076

7177
return client
7278
}
@@ -110,3 +116,7 @@ func (c *standardClient) Models() ModelsClient {
110116
func (c *standardClient) Dashboard() DashboardClient {
111117
return c.dashboardClient
112118
}
119+
120+
func (c *standardClient) Resources() ResourcesClient {
121+
return c.resourcesClient
122+
}

client_fake.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type ClientFake struct {
99
JobsFunc func() JobsClient
1010
ModelsFunc func() ModelsClient
1111
DashboardFunc func() DashboardClient
12+
ResourcesFunc func() ResourcesClient
1213
}
1314

1415
var _ Client = &ClientFake{}
@@ -40,3 +41,7 @@ func (c *ClientFake) Models() ModelsClient {
4041
func (c *ClientFake) Dashboard() DashboardClient {
4142
return c.DashboardFunc()
4243
}
44+
45+
func (c *ClientFake) Resources() ResourcesClient {
46+
return c.ResourcesFunc()
47+
}

client_fake_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ func TestClientFake(t *testing.T) {
4848
calls++
4949
return nil
5050
},
51+
ResourcesFunc: func() ResourcesClient {
52+
calls++
53+
return nil
54+
},
5155
}
5256
fake.WithAPIKey("apiKey")
5357
fake.WithTeamKey("teamID", "token")
@@ -56,8 +60,9 @@ func TestClientFake(t *testing.T) {
5660
fake.Jobs()
5761
fake.Models()
5862
fake.Dashboard()
63+
fake.Resources()
5964

60-
if calls != 7 {
65+
if calls != 8 {
6166
t.Errorf("Did not call all of the funcs: %d", calls)
6267
}
6368
}

internal/testing/main.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,4 +525,37 @@ func getDashboard(client modzy.Client) {
525525
logrus.Info(" ...")
526526
logrus.Infof(" %s: %s", out.Values[len(out.Values)-1].Time, out.Values[len(out.Values)-1].Value)
527527
}
528+
529+
// accounting-users
530+
if out, err := client.Accounting().ListAccountingUsers(ctx, &modzy.ListAccountingUsersInput{}); err != nil {
531+
logrus.WithError(err).Errorf("Failed to get accoutning-users")
532+
} else {
533+
logrus.Infof("Total Users: %d\n", len(out.Users))
534+
}
535+
536+
// license
537+
if out, err := client.Accounting().GetLicense(ctx); err != nil {
538+
logrus.WithError(err).Errorf("Failed to get license")
539+
} else {
540+
logrus.Infof("# Licensed Engines: %s\n", out.License.ProcessingEngines)
541+
}
542+
543+
// engines
544+
if out, err := client.Resources().GetProcessingModels(ctx); err != nil {
545+
logrus.WithError(err).Errorf("Failed to get model resources")
546+
} else {
547+
tot := 0
548+
for _, m := range out.Models {
549+
tot += len(m.Engines)
550+
}
551+
logrus.Infof("# Engines processing : %d\n", tot)
552+
}
553+
554+
// latest models
555+
if out, err := client.Models().GetLatestModels(ctx); err != nil {
556+
logrus.WithError(err).Errorf("Failed to get latest models")
557+
} else {
558+
logrus.Infof("# Latest Models : %d\n", len(out.Models))
559+
}
560+
528561
}

model/accounting.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@ type AccountingUser struct {
1717
Visited bool `json:"visited"`
1818
Onboarded bool `json:"onboarded"`
1919
}
20+
21+
type License struct {
22+
CompanyName string `json:"companyName"`
23+
ProcessingEngines string `json:"processingEngines"`
24+
}

0 commit comments

Comments
 (0)