Skip to content

Commit 0d1ea63

Browse files
committed
get user when username includes @
1 parent a151ca4 commit 0d1ea63

File tree

4 files changed

+141
-1
lines changed

4 files changed

+141
-1
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"size": 2,
3+
"limit": 25,
4+
"isLastPage": true,
5+
"values": [
6+
{
7+
"name": "jane@example",
8+
"emailAddress": "[email protected]",
9+
"id": 1,
10+
"displayName": "Jane Citizen",
11+
"active": true,
12+
"slug": "jane_example",
13+
"type": "NORMAL"
14+
}
15+
],
16+
"start": 0
17+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"Login": "jane_example",
3+
"Name": "Jane Citizen",
4+
"Email": "[email protected]",
5+
"Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg"
6+
}

scm/driver/stash/user.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,38 @@ func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, *
3535
path := fmt.Sprintf("rest/api/1.0/users/%s", login)
3636
out := new(user)
3737
res, err := s.client.do(ctx, "GET", path, nil, out)
38-
return convertUser(out), res, err
38+
if err == nil {
39+
return convertUser(out), res, err
40+
}
41+
42+
// HACK: the below code is a hack to account for the
43+
// fact that the above API call requires the slug,
44+
// but "plugins/servlet/applinks/whoami" may not return
45+
// the slug. When this happens we need to search
46+
// and find the matching user.
47+
48+
// HACK: only use the below special logic for usernames
49+
// that contain an @ symbol.
50+
if !strings.Contains(login, "@") {
51+
return nil, res, err
52+
}
53+
54+
path = fmt.Sprintf("/rest/api/1.0/users?filter=%s", login)
55+
filter := new(userFilter)
56+
res, err = s.client.do(ctx, "GET", path, nil, filter)
57+
if err != nil {
58+
return nil, res, err
59+
}
60+
61+
// iterate through the search results and find
62+
// the username that is an exact match.
63+
for _, item := range filter.Values {
64+
// must be an exact match
65+
if item.Name == login {
66+
return convertUser(item), res, err
67+
}
68+
}
69+
return nil, res, scm.ErrNotFound
3970
}
4071

4172
func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) {
@@ -62,6 +93,10 @@ type user struct {
6293
} `json:"links"`
6394
}
6495

96+
type userFilter struct {
97+
Values []*user `json:"values"`
98+
}
99+
65100
func convertUser(from *user) *scm.User {
66101
return &scm.User{
67102
Avatar: avatarLink(from.EmailAddress),

scm/driver/stash/user_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,24 @@ func TestUserFind(t *testing.T) {
4747
}
4848
}
4949

50+
func TestUserLoginFind_ViaSearch_NotFound(t *testing.T) {
51+
defer gock.Off()
52+
53+
gock.New("https://bitbucket.example.com").
54+
Get("rest/api/1.0/users/jcitizen").
55+
Reply(404)
56+
57+
client, _ := New("https://bitbucket.example.com")
58+
_, _, err := client.Users.FindLogin(context.Background(), "jcitizen")
59+
if err == nil {
60+
t.Errorf("Want ErrNotFound got nil error")
61+
}
62+
63+
if !gock.IsDone() {
64+
t.Errorf("Pending mocks")
65+
}
66+
}
67+
5068
func TestUserLoginFind(t *testing.T) {
5169
defer gock.Off()
5270

@@ -70,6 +88,70 @@ func TestUserLoginFind(t *testing.T) {
7088
t.Errorf("Unexpected Results")
7189
t.Log(diff)
7290
}
91+
92+
if !gock.IsDone() {
93+
t.Errorf("Pending mocks")
94+
}
95+
}
96+
97+
func TestUserLoginFind_ViaSearch(t *testing.T) {
98+
defer gock.Off()
99+
100+
gock.New("https://bitbucket.example.com").
101+
Get("rest/api/1.0/users/jane@example").
102+
Reply(404)
103+
104+
gock.New("https://bitbucket.example.com").
105+
Get("/rest/api/1.0/users").
106+
MatchParam("filter", "jane@example").
107+
Reply(200).
108+
Type("application/json").
109+
File("testdata/user_search.json")
110+
111+
client, _ := New("https://bitbucket.example.com")
112+
got, _, err := client.Users.FindLogin(context.Background(), "jane@example")
113+
if err != nil {
114+
t.Error(err)
115+
return
116+
}
117+
118+
want := new(scm.User)
119+
raw, _ := ioutil.ReadFile("testdata/user_search.json.golden")
120+
json.Unmarshal(raw, &want)
121+
122+
if diff := cmp.Diff(got, want); diff != "" {
123+
t.Errorf("Unexpected Results")
124+
t.Log(diff)
125+
}
126+
127+
if !gock.IsDone() {
128+
t.Errorf("Pending mocks")
129+
}
130+
}
131+
132+
func TestUserLoginFind_ViaSearch_NoMatch(t *testing.T) {
133+
defer gock.Off()
134+
135+
gock.New("https://bitbucket.example.com").
136+
Get("rest/api/1.0/users/john@example").
137+
Reply(404)
138+
139+
gock.New("https://bitbucket.example.com").
140+
Get("/rest/api/1.0/users").
141+
MatchParam("filter", "john@example").
142+
Reply(200).
143+
Type("application/json").
144+
File("testdata/user_search.json")
145+
146+
client, _ := New("https://bitbucket.example.com")
147+
_, _, err := client.Users.FindLogin(context.Background(), "john@example")
148+
if err == nil {
149+
t.Errorf("Want ErrNotFound got nil error")
150+
}
151+
152+
if !gock.IsDone() {
153+
t.Errorf("Pending mocks")
154+
}
73155
}
74156

75157
func TestUserFindEmail(t *testing.T) {

0 commit comments

Comments
 (0)