Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: Allow using username in user queries#1221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Emyrk merged 4 commits intomainfromstevenmasley/user_by_username
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletionscoderd/httpmw/userparam.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,13 @@ import (

type userParamContextKey struct{}

const (
// userErrorMessage is a constant so that no information about the state
// of the queried user can be gained. We return the same error if the user
// does not exist, or if the input is just garbage.
userErrorMessage = "\"user\" must be an existing uuid or username"
)

// UserParam returns the user from the ExtractUserParam handler.
func UserParam(r *http.Request) database.User {
user, ok := r.Context().Value(userParamContextKey{}).(database.User)
Expand All@@ -27,32 +34,56 @@ func UserParam(r *http.Request) database.User {
func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
var userID uuid.UUID
if chi.URLParam(r, "user") == "me" {
userID = APIKey(r).UserID
var user database.User
var err error

// userQuery is either a uuid, a username, or 'me'
userQuery := chi.URLParam(r, "user")
if userQuery == "" {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "\"user\" must be provided",
})
return
}

if userQuery == "me" {
user, err = db.GetUserByID(r.Context(), APIKey(r).UserID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get user: %s", err.Error()),
})
return
}
} else if userID, err := uuid.Parse(userQuery); err == nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

It might reduce complexity if we just disallow getting by UUID entirely. I'm not sure it provides a ton of value anyways, because you need to get the user to get the ID. You could of course list users to do that, but then just use theusername.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'm not inclined to drop the functionality because usernamesmight be able to be changed. UUIDs never will.

It's really nice to have a ID, as you can assume that will be constant no matter what.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Fair enough fair enough

// If the userQuery is a valid uuid
user, err = db.GetUserByID(r.Context(), userID)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: userErrorMessage,
})
return
}
} else {
var ok bool
userID, ok = parseUUID(rw, r, "user")
if !ok {
// Try as a username last
user, err = db.GetUserByEmailOrUsername(r.Context(), database.GetUserByEmailOrUsernameParams{
Username: userQuery,
})
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: userErrorMessage,
})
return
}
}

apiKey := APIKey(r)
if apiKey.UserID !=userID {
if apiKey.UserID !=user.ID {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "getting non-personal users isn't supported yet",
})
return
}

user, err := db.GetUserByID(r.Context(), userID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get user: %s", err.Error()),
})
}

ctx := context.WithValue(r.Context(), userParamContextKey{}, user)
next.ServeHTTP(rw, r.WithContext(ctx))
})
Expand Down
4 changes: 3 additions & 1 deletioncoderd/httpmw/userparam_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,9 @@ func TestUserParam(t *testing.T) {
})

user, err := db.InsertUser(r.Context(), database.InsertUserParams{
ID: uuid.New(),
ID: uuid.New(),
Email: "admin@email.com",
Username: "admin",
})
require.NoError(t, err)

Expand Down
43 changes: 37 additions & 6 deletionscoderd/users_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -431,14 +431,45 @@ func TestPutUserSuspend(t *testing.T) {
})
}

funcTestUserByName(t *testing.T) {
funcTestGetUser(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
firstUser := coderdtest.CreateFirstUser(t, client)
user, err := client.User(context.Background(), codersdk.Me)

require.NoError(t, err)
require.Equal(t, firstUser.OrganizationID, user.OrganizationIDs[0])
t.Run("ByMe", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
firstUser := coderdtest.CreateFirstUser(t, client)

user, err := client.User(context.Background(), codersdk.Me)
require.NoError(t, err)
require.Equal(t, firstUser.UserID, user.ID)
require.Equal(t, firstUser.OrganizationID, user.OrganizationIDs[0])
})

t.Run("ByID", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
firstUser := coderdtest.CreateFirstUser(t, client)

user, err := client.User(context.Background(), firstUser.UserID)
require.NoError(t, err)
require.Equal(t, firstUser.UserID, user.ID)
require.Equal(t, firstUser.OrganizationID, user.OrganizationIDs[0])
})

t.Run("ByUsername", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
firstUser := coderdtest.CreateFirstUser(t, client)
exp, err := client.User(context.Background(), firstUser.UserID)
require.NoError(t, err)

user, err := client.UserByUsername(context.Background(), exp.Username)
require.NoError(t, err)
require.Equal(t, exp, user)
})
}

func TestGetUsers(t *testing.T) {
Expand Down
11 changes: 10 additions & 1 deletioncodersdk/users.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -274,7 +274,16 @@ func (c *Client) Logout(ctx context.Context) error {
// User returns a user for the ID provided.
// If the uuid is nil, the current user will be returned.
func (c *Client) User(ctx context.Context, id uuid.UUID) (User, error) {
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s", uuidOrMe(id)), nil)
return c.userByIdentifier(ctx, uuidOrMe(id))
}

// UserByUsername returns a user for the username provided.
func (c *Client) UserByUsername(ctx context.Context, username string) (User, error) {
return c.userByIdentifier(ctx, username)
}

func (c *Client) userByIdentifier(ctx context.Context, ident string) (User, error) {
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s", ident), nil)
if err != nil {
return User{}, err
}
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp