Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API for Retrieving All Documents #755

Merged
merged 11 commits into from
Jan 12, 2024
9 changes: 9 additions & 0 deletions server/backend/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ type Database interface {
publicKey string,
) (*ProjectInfo, error)

// FindProjectInfoBySecretKey returns a project by secret key.
FindProjectInfoBySecretKey(
ctx context.Context,
secretKey string,
) (*ProjectInfo, error)

// FindProjectInfoByName returns a project by the given name.
FindProjectInfoByName(
ctx context.Context,
Expand Down Expand Up @@ -118,6 +124,9 @@ type Database interface {
// FindUserInfo returns a user by the given username.
FindUserInfo(ctx context.Context, username string) (*UserInfo, error)

// FindUserInfoByID finds a user by the given id.
FindUserInfoByID(ctx context.Context, id types.ID) (*UserInfo, error)

// ListUserInfos returns all users.
ListUserInfos(ctx context.Context) ([]*UserInfo, error)

Expand Down
35 changes: 35 additions & 0 deletions server/backend/database/memory/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,25 @@ func (d *DB) FindProjectInfoByPublicKey(
return raw.(*database.ProjectInfo).DeepCopy(), nil
}

// FindProjectInfoBySecretKey returns a project by secret key.
func (d *DB) FindProjectInfoBySecretKey(
_ context.Context,
secretKey string,
) (*database.ProjectInfo, error) {
txn := d.db.Txn(false)
defer txn.Abort()

raw, err := txn.First(tblProjects, "secret_key", secretKey)
if err != nil {
return nil, fmt.Errorf("find project by secret key: %w", err)
}
if raw == nil {
return nil, fmt.Errorf("%s: %w", secretKey, database.ErrProjectNotFound)
}

return raw.(*database.ProjectInfo).DeepCopy(), nil
}

// FindProjectInfoByName returns a project by the given name.
func (d *DB) FindProjectInfoByName(
_ context.Context,
Expand Down Expand Up @@ -379,6 +398,22 @@ func (d *DB) FindUserInfo(_ context.Context, username string) (*database.UserInf
return raw.(*database.UserInfo).DeepCopy(), nil
}

// FindUserInfoByID finds a user by the given ID.
func (d *DB) FindUserInfoByID(_ context.Context, clientID types.ID) (*database.UserInfo, error) {
txn := d.db.Txn(false)
defer txn.Abort()

raw, err := txn.First(tblUsers, "id", clientID.String())
if err != nil {
return nil, fmt.Errorf("find user by id: %w", err)
}
if raw == nil {
return nil, fmt.Errorf("%s: %w", clientID, database.ErrUserNotFound)
}

return raw.(*database.UserInfo).DeepCopy(), nil
}

// ListUserInfos returns all users.
func (d *DB) ListUserInfos(_ context.Context) ([]*database.UserInfo, error) {
txn := d.db.Txn(false)
Expand Down
8 changes: 8 additions & 0 deletions server/backend/database/memory/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ func TestDB(t *testing.T) {
testcases.RunListUserInfosTest(t, db)
})

t.Run("FindUserInfoByID test", func(t *testing.T) {
testcases.RunFindUserInfoByIDTest(t, db)
})

t.Run("FindProjectInfoBySecretKey test", func(t *testing.T) {
testcases.RunFindProjectInfoBySecretKeyTest(t, db)
})

t.Run("FindProjectInfoByName test", func(t *testing.T) {
testcases.RunFindProjectInfoByNameTest(t, db)
})
Expand Down
39 changes: 39 additions & 0 deletions server/backend/database/mongo/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,23 @@ func (c *Client) FindProjectInfoByPublicKey(ctx context.Context, publicKey strin
return &projectInfo, nil
}

// FindProjectInfoBySecretKey returns a project by secret key.
func (c *Client) FindProjectInfoBySecretKey(ctx context.Context, secretKey string) (*database.ProjectInfo, error) {
result := c.collection(colProjects).FindOne(ctx, bson.M{
"secret_key": secretKey,
})

projectInfo := database.ProjectInfo{}
if err := result.Decode(&projectInfo); err != nil {
if err == mongo.ErrNoDocuments {
return nil, fmt.Errorf("%s: %w", secretKey, database.ErrProjectNotFound)
}
return nil, fmt.Errorf("decode project info: %w", err)
}

return &projectInfo, nil
}

// FindProjectInfoByName returns a project by name.
func (c *Client) FindProjectInfoByName(
ctx context.Context,
Expand Down Expand Up @@ -468,6 +485,28 @@ func (c *Client) ListUserInfos(
return infos, nil
}

// FindUserInfoByID returns a user by ID.
func (c *Client) FindUserInfoByID(ctx context.Context, clientID types.ID) (*database.UserInfo, error) {
encodedClientID, err := encodeID(clientID)
if err != nil {
return nil, err
}

result := c.collection(colUsers).FindOne(ctx, bson.M{
"_id": encodedClientID,
})

userInfo := database.UserInfo{}
if err := result.Decode(&userInfo); err != nil {
if err == mongo.ErrNoDocuments {
return nil, fmt.Errorf("%s: %w", clientID, database.ErrUserNotFound)
}
return nil, fmt.Errorf("decode user info: %w", err)
}

return &userInfo, nil
}

// ActivateClient activates the client of the given key.
func (c *Client) ActivateClient(ctx context.Context, projectID types.ID, key string) (*database.ClientInfo, error) {
encodedProjectID, err := encodeID(projectID)
Expand Down
8 changes: 8 additions & 0 deletions server/backend/database/mongo/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ func TestClient(t *testing.T) {
testcases.RunListUserInfosTest(t, cli)
})

t.Run("FindUserInfoByID test", func(t *testing.T) {
testcases.RunFindUserInfoByIDTest(t, cli)
})

t.Run("FindProjectInfoBySecretKey test", func(t *testing.T) {
testcases.RunFindProjectInfoBySecretKeyTest(t, cli)
})

t.Run("FindProjectInfoByName test", func(t *testing.T) {
testcases.RunFindProjectInfoByNameTest(t, cli)
})
Expand Down
39 changes: 39 additions & 0 deletions server/backend/database/testcases/testcases.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,27 @@ func RunFindDocInfoTest(
})
}

// RunFindProjectInfoBySecretKeyTest runs the FindProjectInfoBySecretKey test for the given db.
func RunFindProjectInfoBySecretKeyTest(
t *testing.T,
db database.Database,
) {
t.Run("FindProjectInfoBySecretKey test", func(t *testing.T) {
ctx := context.Background()

username := "[email protected]"
password := "hashed-password"

_, project, err := db.EnsureDefaultUserAndProject(ctx, username, password, clientDeactivateThreshold)
assert.NoError(t, err)

info2, err := db.FindProjectInfoBySecretKey(ctx, project.SecretKey)
assert.NoError(t, err)

assert.Equal(t, project.ID, info2.ID)
})
}

// RunFindProjectInfoByNameTest runs the FindProjectInfoByName test for the given db.
func RunFindProjectInfoByNameTest(
t *testing.T,
Expand Down Expand Up @@ -274,6 +295,24 @@ func RunListUserInfosTest(t *testing.T, db database.Database) {
})
}

// RunFindUserInfoByIDTest runs the FindUserInfoByID test for the given db.
func RunFindUserInfoByIDTest(t *testing.T, db database.Database) {
t.Run("RunFindUserInfoByID test", func(t *testing.T) {
ctx := context.Background()

username := "findUserInfoTestAccount"
password := "temporary-password"

user, _, err := db.EnsureDefaultUserAndProject(ctx, username, password, clientDeactivateThreshold)
assert.NoError(t, err)

info1, err := db.FindUserInfoByID(ctx, user.ID)
assert.NoError(t, err)

assert.Equal(t, user.ID, info1.ID)
})
}

// RunActivateClientDeactivateClientTest runs the ActivateClient and DeactivateClient tests for the given db.
func RunActivateClientDeactivateClientTest(t *testing.T, db database.Database, projectID types.ID) {
t.Run("activate and find client test", func(t *testing.T) {
Expand Down
11 changes: 11 additions & 0 deletions server/projects/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func UpdateProject(

// GetProjectFromAPIKey returns a project from an API key.
func GetProjectFromAPIKey(ctx context.Context, be *backend.Backend, apiKey string) (*types.Project, error) {
// TODO(hackerwins): Default project without API key should be allowed only in standalone mode.
if apiKey == "" {
info, err := be.DB.FindProjectInfoByID(ctx, database.DefaultProjectID)
if err != nil {
Expand All @@ -107,3 +108,13 @@ func GetProjectFromAPIKey(ctx context.Context, be *backend.Backend, apiKey strin

return info.ToProject(), nil
}

// GetProjectFromSecretKey returns a project from a secret key.
func GetProjectFromSecretKey(ctx context.Context, be *backend.Backend, secretKey string) (*types.Project, error) {
info, err := be.DB.FindProjectInfoBySecretKey(ctx, secretKey)
if err != nil {
return nil, err
}

return info.ToProject(), nil
}
21 changes: 15 additions & 6 deletions server/rpc/interceptors/admin_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

"github.com/yorkie-team/yorkie/api/types"
"github.com/yorkie-team/yorkie/server/backend"
"github.com/yorkie-team/yorkie/server/projects"
"github.com/yorkie-team/yorkie/server/rpc/auth"
"github.com/yorkie-team/yorkie/server/rpc/connecthelper"
"github.com/yorkie-team/yorkie/server/users"
Expand Down Expand Up @@ -161,15 +162,23 @@ func (i *AdminAuthInterceptor) authenticate(
return nil, connect.NewError(connect.CodeUnauthenticated, ErrUnauthenticated)
}

// NOTE(raararaara): If the token is access token, return the user of the token.
claims, err := i.tokenManager.Verify(authorization)
if err != nil {
return nil, connect.NewError(connect.CodeUnauthenticated, ErrUnauthenticated)
if err == nil {
user, err := users.GetUser(ctx, i.backend, claims.Username)
if err == nil {
return user, nil
}
}

user, err := users.GetUser(ctx, i.backend, claims.Username)
if err != nil {
return nil, connect.NewError(connect.CodeUnauthenticated, ErrUnauthenticated)
// NOTE(raararaara): If the token is secret key, return the owner of the project.
project, err := projects.GetProjectFromSecretKey(ctx, i.backend, authorization)
if err == nil {
user, err := users.GetUserByID(ctx, i.backend, project.Owner)
if err == nil {
return user, nil
}
}

return user, nil
return nil, connect.NewError(connect.CodeUnauthenticated, ErrUnauthenticated)
}
13 changes: 13 additions & 0 deletions server/users/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,16 @@ func GetUser(

return info.ToUser(), nil
}

// GetUserByID returns a user by ID.
func GetUserByID(
ctx context.Context,
be *backend.Backend,
id types.ID,
) (*types.User, error) {
info, err := be.DB.FindUserInfoByID(ctx, id)
if err != nil {
return nil, err
}
return info.ToUser(), nil
}
Loading