jira-cli/pkg/jira/user.go

106 lines
2.8 KiB
Go

package jira
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
// ErrInvalidSearchOption denotes invalid search option was given.
var ErrInvalidSearchOption = fmt.Errorf("invalid search option")
// UserSearchOptions holds options to search for user.
type UserSearchOptions struct {
Project string
Query string
Username string
AccountID string
StartAt int
MaxResults int
}
// UserSearch search for user details using v3 version of the GET /user/assignable/search endpoint.
func (c *Client) UserSearch(opt *UserSearchOptions) ([]*User, error) {
return c.userSearch(opt, apiVersion3)
}
// UserSearchV2 search for user details using v2 version of the GET /user/assignable/search endpoint.
func (c *Client) UserSearchV2(opt *UserSearchOptions) ([]*User, error) {
// The `username` query param is deprecated since Jira API v2 and is not available in v3.
// Since the` query` parameter doesn't seem to return expected results, we will use the
// `username` param in call to v2. Chances are the `query` param may stop working in
// later v2 updates so we might have to revisit this in the future. Note that the
// `username` param is not as flexible as the `query` param available in v3.
//
// See https://github.com/ankitpokhrel/jira-cli/issues/198
if opt.Query != "" && opt.Username == "" {
opt.Username = opt.Query
opt.Query = ""
}
return c.userSearch(opt, apiVersion2)
}
func (c *Client) userSearch(opt *UserSearchOptions, ver string) ([]*User, error) {
if opt == nil {
return nil, ErrInvalidSearchOption
}
var (
opts []string
res *http.Response
err error
)
if opt.Project != "" {
opts = append(opts, fmt.Sprintf("project=%s", opt.Project))
}
if opt.Query != "" {
opts = append(opts, fmt.Sprintf("query=%s", url.QueryEscape(opt.Query)))
}
if opt.Username != "" {
opts = append(opts, fmt.Sprintf("username=%s", url.QueryEscape(opt.Username)))
}
if opt.AccountID != "" {
opts = append(opts, fmt.Sprintf("accountId=%s", url.QueryEscape(opt.AccountID)))
}
if opt.StartAt != 0 {
opts = append(opts, fmt.Sprintf("startAt=%d", opt.StartAt))
}
if opt.MaxResults != 0 {
opts = append(opts, fmt.Sprintf("maxResults=%d", opt.MaxResults))
}
if len(opts) == 0 {
return nil, ErrInvalidSearchOption
}
path := fmt.Sprintf("%s?%s", "/user/assignable/search", strings.Join(opts, "&"))
switch ver {
case apiVersion2:
res, err = c.GetV2(context.Background(), path, nil)
default:
res, err = c.Get(context.Background(), path, nil)
}
if err != nil {
return nil, err
}
if res == nil {
return nil, ErrEmptyResponse
}
defer func() { _ = res.Body.Close() }()
if res.StatusCode != http.StatusOK {
return nil, formatUnexpectedResponse(res)
}
var out []*User
if err := json.NewDecoder(res.Body).Decode(&out); err != nil {
return nil, err
}
return out, nil
}