1// Copyright 2016 Circonus, Inc. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// User API support - Fetch, Update, and Search
6// See: https://login.circonus.com/resources/api/calls/user
7// Note: Create and Delete are not supported directly via the User API
8// endpoint. See the Account endpoint for inviting and removing users
9// from specific accounts.
10
11package api
12
13import (
14	"encoding/json"
15	"fmt"
16	"net/url"
17	"regexp"
18
19	"github.com/circonus-labs/circonus-gometrics/api/config"
20)
21
22// UserContactInfo defines known contact details
23type UserContactInfo struct {
24	SMS  string `json:"sms,omitempty"`  // string
25	XMPP string `json:"xmpp,omitempty"` // string
26}
27
28// User defines a user. See https://login.circonus.com/resources/api/calls/user for more information.
29type User struct {
30	CID         string          `json:"_cid,omitempty"`         // string
31	ContactInfo UserContactInfo `json:"contact_info,omitempty"` // UserContactInfo
32	Email       string          `json:"email"`                  // string
33	Firstname   string          `json:"firstname"`              // string
34	Lastname    string          `json:"lastname"`               // string
35}
36
37// FetchUser retrieves user with passed cid. Pass nil for '/user/current'.
38func (a *API) FetchUser(cid CIDType) (*User, error) {
39	var userCID string
40
41	if cid == nil || *cid == "" {
42		userCID = config.UserPrefix + "/current"
43	} else {
44		userCID = string(*cid)
45	}
46
47	matched, err := regexp.MatchString(config.UserCIDRegex, userCID)
48	if err != nil {
49		return nil, err
50	}
51	if !matched {
52		return nil, fmt.Errorf("Invalid user CID [%s]", userCID)
53	}
54
55	result, err := a.Get(userCID)
56	if err != nil {
57		return nil, err
58	}
59
60	if a.Debug {
61		a.Log.Printf("[DEBUG] fetch user, received JSON: %s", string(result))
62	}
63
64	user := new(User)
65	if err := json.Unmarshal(result, user); err != nil {
66		return nil, err
67	}
68
69	return user, nil
70}
71
72// FetchUsers retrieves all users available to API Token.
73func (a *API) FetchUsers() (*[]User, error) {
74	result, err := a.Get(config.UserPrefix)
75	if err != nil {
76		return nil, err
77	}
78
79	var users []User
80	if err := json.Unmarshal(result, &users); err != nil {
81		return nil, err
82	}
83
84	return &users, nil
85}
86
87// UpdateUser updates passed user.
88func (a *API) UpdateUser(cfg *User) (*User, error) {
89	if cfg == nil {
90		return nil, fmt.Errorf("Invalid user config [nil]")
91	}
92
93	userCID := string(cfg.CID)
94
95	matched, err := regexp.MatchString(config.UserCIDRegex, userCID)
96	if err != nil {
97		return nil, err
98	}
99	if !matched {
100		return nil, fmt.Errorf("Invalid user CID [%s]", userCID)
101	}
102
103	jsonCfg, err := json.Marshal(cfg)
104	if err != nil {
105		return nil, err
106	}
107
108	if a.Debug {
109		a.Log.Printf("[DEBUG] update user, sending JSON: %s", string(jsonCfg))
110	}
111
112	result, err := a.Put(userCID, jsonCfg)
113	if err != nil {
114		return nil, err
115	}
116
117	user := &User{}
118	if err := json.Unmarshal(result, user); err != nil {
119		return nil, err
120	}
121
122	return user, nil
123}
124
125// SearchUsers returns users matching a filter (search queries
126// are not suppoted by the user endpoint). Pass nil as filter for all
127// users available to the API Token.
128func (a *API) SearchUsers(filterCriteria *SearchFilterType) (*[]User, error) {
129	q := url.Values{}
130
131	if filterCriteria != nil && len(*filterCriteria) > 0 {
132		for filter, criteria := range *filterCriteria {
133			for _, val := range criteria {
134				q.Add(filter, val)
135			}
136		}
137	}
138
139	if q.Encode() == "" {
140		return a.FetchUsers()
141	}
142
143	reqURL := url.URL{
144		Path:     config.UserPrefix,
145		RawQuery: q.Encode(),
146	}
147
148	result, err := a.Get(reqURL.String())
149	if err != nil {
150		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
151	}
152
153	var users []User
154	if err := json.Unmarshal(result, &users); err != nil {
155		return nil, err
156	}
157
158	return &users, nil
159}
160