feat: add a new REST endpoint - GET /api/v1/user/sessions/:server (#14)
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Reviewed-on: #14
This commit is contained in:
parent
5872ead643
commit
786cc60e38
|
@ -38,7 +38,7 @@ func TestAPIKey_Create(t *testing.T) {
|
|||
t.Run("ERR: user doesn't exist", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params, err := domain.NewCreateAPIKeyParams(uuid.NewString(), fixture.user(t, "user-1").ID+1)
|
||||
params, err := domain.NewCreateAPIKeyParams(uuid.NewString(), fixture.user(t, "user-1").ID+11111)
|
||||
require.NoError(t, err)
|
||||
|
||||
apiKey, err := repo.Create(context.Background(), params)
|
||||
|
|
|
@ -162,6 +162,16 @@ func (f *bunfixture) apiKey(tb testing.TB, id string) domain.APIKey {
|
|||
return ak.ToDomain()
|
||||
}
|
||||
|
||||
func (f *bunfixture) session(tb testing.TB, id string) domain.Session {
|
||||
tb.Helper()
|
||||
|
||||
row, err := f.Row("Session." + id)
|
||||
require.NoError(tb, err)
|
||||
sess, ok := row.(*model.Session)
|
||||
require.True(tb, ok)
|
||||
return sess.ToDomain()
|
||||
}
|
||||
|
||||
func generateSchema() string {
|
||||
return strings.TrimFunc(strings.ReplaceAll(uuid.NewString(), "-", "_"), unicode.IsNumber)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package bundb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
|
@ -20,10 +21,10 @@ func NewSession(db *bun.DB) *Session {
|
|||
return &Session{db: db}
|
||||
}
|
||||
|
||||
func (u *Session) CreateOrUpdate(ctx context.Context, params domain.CreateSessionParams) (domain.Session, error) {
|
||||
func (s *Session) CreateOrUpdate(ctx context.Context, params domain.CreateSessionParams) (domain.Session, error) {
|
||||
sess := model.NewSession(params)
|
||||
|
||||
if _, err := u.db.NewInsert().
|
||||
if _, err := s.db.NewInsert().
|
||||
Model(&sess).
|
||||
On("CONFLICT ON CONSTRAINT sessions_user_id_server_key_key DO UPDATE").
|
||||
Set("sid = EXCLUDED.sid").
|
||||
|
@ -39,6 +40,28 @@ func (u *Session) CreateOrUpdate(ctx context.Context, params domain.CreateSessio
|
|||
return sess.ToDomain(), nil
|
||||
}
|
||||
|
||||
func (s *Session) Get(ctx context.Context, userID int64, serverKey string) (domain.Session, error) {
|
||||
var sess model.Session
|
||||
|
||||
if err := s.db.NewSelect().
|
||||
Model(&sess).
|
||||
Where("user_id = ?", userID).
|
||||
Where("server_key = ?", serverKey).
|
||||
Scan(ctx); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return domain.Session{}, domain.SessionNotFoundError{ServerKey: serverKey}
|
||||
}
|
||||
return domain.Session{}, fmt.Errorf(
|
||||
"something went wrong while selecting sess (userID=%d,serverKey=%s) from the db: %w",
|
||||
userID,
|
||||
serverKey,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
return sess.ToDomain(), nil
|
||||
}
|
||||
|
||||
func mapCreateSessionError(err error, params domain.CreateSessionParams) error {
|
||||
var pgError pgdriver.Error
|
||||
if !errors.As(err, &pgError) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package bundb_test
|
|||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -73,3 +74,52 @@ func TestSession_CreateOrUpdate(t *testing.T) {
|
|||
assert.Zero(t, sess)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSession_Get(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := newDB(t)
|
||||
fixture := loadFixtures(t, db)
|
||||
repo := bundb.NewSession(db)
|
||||
sessFixture := fixture.session(t, "user-1-session-1")
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
sess, err := repo.Get(context.Background(), sessFixture.UserID, sessFixture.ServerKey)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, sessFixture, sess)
|
||||
})
|
||||
|
||||
t.Run("ERR: session not found", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
userID int64
|
||||
serverKey string
|
||||
}{
|
||||
{
|
||||
userID: sessFixture.UserID + 11111,
|
||||
serverKey: sessFixture.ServerKey,
|
||||
},
|
||||
{
|
||||
userID: sessFixture.UserID,
|
||||
serverKey: sessFixture.ServerKey + "1111",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(fmt.Sprintf("UserID=%d,ServerKey=%s", tt.userID, tt.serverKey), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
sess, err := repo.Get(context.Background(), tt.userID, tt.serverKey)
|
||||
assert.ErrorIs(t, err, domain.SessionNotFoundError{
|
||||
ServerKey: tt.serverKey,
|
||||
})
|
||||
assert.Zero(t, sess)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,10 +5,38 @@
|
|||
name: User-1
|
||||
name_lower: user-1
|
||||
created_at: 2022-03-15T15:00:10.000Z
|
||||
- _id: user-2
|
||||
id: 11112
|
||||
name: User-2
|
||||
name_lower: user-2
|
||||
created_at: 2022-04-15T15:00:10.000Z
|
||||
- model: APIKey
|
||||
rows:
|
||||
- _id: user-1-api-key-1
|
||||
id: 11111
|
||||
key: 4c0d2d63-4ef7-4c23-bb4d-f3646cc9658f
|
||||
user_id: 11111
|
||||
created_at: 2022-03-15T15:15:10.000Z
|
||||
created_at: 2022-03-15T15:15:10.000Z
|
||||
- model: Session
|
||||
rows:
|
||||
- _id: user-1-session-1
|
||||
id: 111111
|
||||
user_id: 11111
|
||||
server_key: pl181
|
||||
sid: NzM3NjgzZmMtYWNlNC00MTI4LThiNWYtMWRlNTYwYjdjNmUx
|
||||
created_at: 2022-03-15T15:15:10.000Z
|
||||
updated_at: 2022-03-15T15:15:10.000Z
|
||||
- _id: user-1-session-2
|
||||
id: 111112
|
||||
user_id: 11111
|
||||
server_key: pl183
|
||||
sid: NzM3NjgzZmMtYWNlNC00MTI4LThiNWYtMWRlNTYwYjdjNmUx
|
||||
created_at: 2022-03-25T15:15:10.000Z
|
||||
updated_at: 2022-03-25T15:15:10.000Z
|
||||
- _id: user-2-session-1
|
||||
id: 111121
|
||||
user_id: 11112
|
||||
server_key: pl181
|
||||
sid: NzM3NjgzZmMtYWNlNC00MTI4LThiNWYtMWRlNTYwYjdjNmUx
|
||||
created_at: 2022-04-25T15:15:10.000Z
|
||||
updated_at: 2022-04-25T15:15:10.000Z
|
|
@ -80,9 +80,9 @@ func TestUser_Get(t *testing.T) {
|
|||
t.Run("ERR: user not found", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
user, err := repo.Get(context.Background(), userFromFixture.ID+1)
|
||||
user, err := repo.Get(context.Background(), userFromFixture.ID+1111111)
|
||||
assert.ErrorIs(t, err, domain.UserNotFoundError{
|
||||
ID: userFromFixture.ID + 1,
|
||||
ID: userFromFixture.ID + 1111111,
|
||||
})
|
||||
assert.Zero(t, user)
|
||||
})
|
||||
|
|
|
@ -2,6 +2,7 @@ package domain
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -83,3 +84,19 @@ func isBase64(s string) bool {
|
|||
_, err := base64.StdEncoding.DecodeString(s)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
type SessionNotFoundError struct {
|
||||
ServerKey string
|
||||
}
|
||||
|
||||
func (e SessionNotFoundError) Error() string {
|
||||
return fmt.Sprintf("session (ServerKey=%s) not found", e.ServerKey)
|
||||
}
|
||||
|
||||
func (e SessionNotFoundError) UserError() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
func (e SessionNotFoundError) Code() ErrorCode {
|
||||
return ErrorCodeEntityNotFound
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package domain_test
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/domain"
|
||||
|
@ -101,3 +102,15 @@ func TestNewCreateSessionParams(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionNotFoundError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := domain.SessionNotFoundError{
|
||||
ServerKey: "pl151",
|
||||
}
|
||||
var _ domain.Error = err
|
||||
assert.Equal(t, fmt.Sprintf("session (ServerKey=%s) not found", err.ServerKey), err.Error())
|
||||
assert.Equal(t, err.Error(), err.UserError())
|
||||
assert.Equal(t, domain.ErrorCodeEntityNotFound, err.Code())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package model
|
||||
|
||||
import "gitea.dwysokinski.me/twhelp/sessions/internal/domain"
|
||||
|
||||
type Session struct {
|
||||
ServerKey string `json:"serverKey"`
|
||||
SID string `json:"sid"`
|
||||
} // @name Session
|
||||
|
||||
func NewSession(s domain.Session) Session {
|
||||
return Session{
|
||||
ServerKey: s.ServerKey,
|
||||
SID: s.SID,
|
||||
}
|
||||
}
|
||||
|
||||
type GetSessionResp struct {
|
||||
Data Session `json:"data"`
|
||||
} // @name GetSessionResp
|
||||
|
||||
func NewGetSessionResp(s domain.Session) GetSessionResp {
|
||||
return GetSessionResp{Data: NewSession(s)}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package model_test
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/domain"
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/router/rest/internal/model"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewSession(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
sess := domain.Session{
|
||||
ID: 1111,
|
||||
UserID: 111,
|
||||
ServerKey: "pl151",
|
||||
SID: base64.StdEncoding.EncodeToString([]byte(uuid.NewString())),
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
assertSession(t, sess, model.NewSession(sess))
|
||||
}
|
||||
|
||||
func TestNewGetSessionResp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
sess := domain.Session{
|
||||
ID: 1111,
|
||||
UserID: 111,
|
||||
ServerKey: "pl151",
|
||||
SID: base64.StdEncoding.EncodeToString([]byte(uuid.NewString())),
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
assertSession(t, sess, model.NewGetSessionResp(sess).Data)
|
||||
}
|
||||
|
||||
func assertSession(tb testing.TB, du domain.Session, ru model.Session) {
|
||||
tb.Helper()
|
||||
|
||||
assert.Equal(tb, du.ServerKey, ru.ServerKey)
|
||||
assert.Equal(tb, du.SID, ru.SID)
|
||||
}
|
|
@ -71,8 +71,9 @@ func NewRouter(cfg RouterConfig) *chi.Mux {
|
|||
|
||||
authMw := authMiddleware(cfg.APIKeyVerifier)
|
||||
|
||||
r.With(authMw).Get("/user", uh.getAuthenticated)
|
||||
r.With(authMw).Get("/user", uh.getCurrent)
|
||||
r.With(authMw).Put("/user/sessions/{serverKey}", sh.createOrUpdate)
|
||||
r.With(authMw).Get("/user/sessions/{serverKey}", sh.getCurrentUser)
|
||||
})
|
||||
|
||||
return router
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/domain"
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/router/rest/internal/model"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
|
@ -16,6 +17,7 @@ const (
|
|||
//counterfeiter:generate -o internal/mock/session_service.gen.go . SessionService
|
||||
type SessionService interface {
|
||||
CreateOrUpdate(ctx context.Context, params domain.CreateSessionParams) (domain.Session, error)
|
||||
Get(ctx context.Context, userID int64, serverKey string) (domain.Session, error)
|
||||
}
|
||||
|
||||
type sessionHandler struct {
|
||||
|
@ -28,8 +30,8 @@ type sessionHandler struct {
|
|||
// @Tags users,sessions
|
||||
// @Accept plain
|
||||
// @Success 204
|
||||
// @Success 400 {object} model.ErrorResp
|
||||
// @Success 401 {object} model.ErrorResp
|
||||
// @Failure 400 {object} model.ErrorResp
|
||||
// @Failure 401 {object} model.ErrorResp
|
||||
// @Failure 500 {object} model.ErrorResp
|
||||
// @Security ApiKeyAuth
|
||||
// @Param serverKey path string true "Server key"
|
||||
|
@ -60,3 +62,29 @@ func (h *sessionHandler) createOrUpdate(w http.ResponseWriter, r *http.Request)
|
|||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// @ID getCurrentUserSession
|
||||
// @Summary Get a session
|
||||
// @Description Get a session
|
||||
// @Tags users,sessions
|
||||
// @Success 200 {object} model.GetSessionResp
|
||||
// @Failure 400 {object} model.ErrorResp
|
||||
// @Failure 401 {object} model.ErrorResp
|
||||
// @Failure 404 {object} model.ErrorResp
|
||||
// @Failure 500 {object} model.ErrorResp
|
||||
// @Security ApiKeyAuth
|
||||
// @Param serverKey path string true "Server key"
|
||||
// @Router /user/sessions/{serverKey} [get]
|
||||
func (h *sessionHandler) getCurrentUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
chiCtx := chi.RouteContext(ctx)
|
||||
user, _ := userFromContext(ctx)
|
||||
|
||||
sess, err := h.svc.Get(ctx, user.ID, chiCtx.URLParam("serverKey"))
|
||||
if err != nil {
|
||||
renderErr(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
renderJSON(w, http.StatusOK, model.NewGetSessionResp(sess))
|
||||
}
|
||||
|
|
|
@ -34,19 +34,11 @@ func TestSession_createOrUpdate(t *testing.T) {
|
|||
{
|
||||
name: "OK",
|
||||
setup: func(apiKeySvc *mock.FakeAPIKeyVerifier, sessionSvc *mock.FakeSessionService) {
|
||||
apiKeySvc.VerifyCalls(func(ctx context.Context, key string) (domain.User, error) {
|
||||
if key != apiKey {
|
||||
return domain.User{}, domain.APIKeyNotFoundError{
|
||||
Key: key,
|
||||
}
|
||||
}
|
||||
|
||||
return domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil
|
||||
})
|
||||
apiKeySvc.VerifyReturns(domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil)
|
||||
sessionSvc.CreateOrUpdateReturns(domain.Session{}, nil)
|
||||
},
|
||||
apiKey: apiKey,
|
||||
|
@ -57,19 +49,11 @@ func TestSession_createOrUpdate(t *testing.T) {
|
|||
{
|
||||
name: "ERR: len(serverKey) > 10",
|
||||
setup: func(apiKeySvc *mock.FakeAPIKeyVerifier, sessionSvc *mock.FakeSessionService) {
|
||||
apiKeySvc.VerifyCalls(func(ctx context.Context, key string) (domain.User, error) {
|
||||
if key != apiKey {
|
||||
return domain.User{}, domain.APIKeyNotFoundError{
|
||||
Key: key,
|
||||
}
|
||||
}
|
||||
|
||||
return domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil
|
||||
})
|
||||
apiKeySvc.VerifyReturns(domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil)
|
||||
},
|
||||
apiKey: apiKey,
|
||||
serverKey: "012345678890",
|
||||
|
@ -86,19 +70,11 @@ func TestSession_createOrUpdate(t *testing.T) {
|
|||
{
|
||||
name: "ERR: SID is required",
|
||||
setup: func(apiKeySvc *mock.FakeAPIKeyVerifier, sessionSvc *mock.FakeSessionService) {
|
||||
apiKeySvc.VerifyCalls(func(ctx context.Context, key string) (domain.User, error) {
|
||||
if key != apiKey {
|
||||
return domain.User{}, domain.APIKeyNotFoundError{
|
||||
Key: key,
|
||||
}
|
||||
}
|
||||
|
||||
return domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil
|
||||
})
|
||||
apiKeySvc.VerifyReturns(domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil)
|
||||
},
|
||||
apiKey: apiKey,
|
||||
serverKey: "pl151",
|
||||
|
@ -115,19 +91,11 @@ func TestSession_createOrUpdate(t *testing.T) {
|
|||
{
|
||||
name: "ERR: SID is not a valid base64",
|
||||
setup: func(apiKeySvc *mock.FakeAPIKeyVerifier, sessionSvc *mock.FakeSessionService) {
|
||||
apiKeySvc.VerifyCalls(func(ctx context.Context, key string) (domain.User, error) {
|
||||
if key != apiKey {
|
||||
return domain.User{}, domain.APIKeyNotFoundError{
|
||||
Key: key,
|
||||
}
|
||||
}
|
||||
|
||||
return domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil
|
||||
})
|
||||
apiKeySvc.VerifyReturns(domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil)
|
||||
},
|
||||
apiKey: apiKey,
|
||||
serverKey: "pl151",
|
||||
|
@ -216,3 +184,139 @@ func TestSession_createOrUpdate(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSession_getCurrentUser(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Now()
|
||||
apiKey := uuid.NewString()
|
||||
sid := base64.StdEncoding.EncodeToString([]byte(uuid.NewString()))
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(*mock.FakeAPIKeyVerifier, *mock.FakeSessionService)
|
||||
apiKey string
|
||||
serverKey string
|
||||
expectedStatus int
|
||||
target any
|
||||
expectedResponse any
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
setup: func(apiKeySvc *mock.FakeAPIKeyVerifier, sessionSvc *mock.FakeSessionService) {
|
||||
apiKeySvc.VerifyReturns(domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil)
|
||||
sessionSvc.GetCalls(func(ctx context.Context, userID int64, serverKey string) (domain.Session, error) {
|
||||
return domain.Session{
|
||||
ID: 111,
|
||||
UserID: userID,
|
||||
ServerKey: serverKey,
|
||||
SID: sid,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}, nil
|
||||
})
|
||||
},
|
||||
apiKey: apiKey,
|
||||
serverKey: "pl151",
|
||||
expectedStatus: http.StatusOK,
|
||||
target: &model.GetSessionResp{},
|
||||
expectedResponse: &model.GetSessionResp{
|
||||
Data: model.Session{
|
||||
ServerKey: "pl151",
|
||||
SID: sid,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: session not found",
|
||||
setup: func(apiKeySvc *mock.FakeAPIKeyVerifier, sessionSvc *mock.FakeSessionService) {
|
||||
apiKeySvc.VerifyReturns(domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil)
|
||||
sessionSvc.GetCalls(func(ctx context.Context, userID int64, serverKey string) (domain.Session, error) {
|
||||
return domain.Session{}, domain.SessionNotFoundError{
|
||||
ServerKey: serverKey,
|
||||
}
|
||||
})
|
||||
},
|
||||
apiKey: apiKey,
|
||||
expectedStatus: http.StatusNotFound,
|
||||
serverKey: "pl151",
|
||||
target: &model.ErrorResp{},
|
||||
expectedResponse: &model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: domain.ErrorCodeEntityNotFound.String(),
|
||||
Message: "session (ServerKey=pl151) not found",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: apiKey == \"\"",
|
||||
setup: func(apiKeySvc *mock.FakeAPIKeyVerifier, sessionSvc *mock.FakeSessionService) {},
|
||||
apiKey: "",
|
||||
expectedStatus: http.StatusUnauthorized,
|
||||
serverKey: "pl151",
|
||||
target: &model.ErrorResp{},
|
||||
expectedResponse: &model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: "unauthorized",
|
||||
Message: "invalid API key",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: unexpected API key",
|
||||
setup: func(apiKeySvc *mock.FakeAPIKeyVerifier, sessionSvc *mock.FakeSessionService) {
|
||||
apiKeySvc.VerifyCalls(func(ctx context.Context, key string) (domain.User, error) {
|
||||
if key != apiKey {
|
||||
return domain.User{}, domain.APIKeyNotFoundError{
|
||||
Key: key,
|
||||
}
|
||||
}
|
||||
|
||||
return domain.User{
|
||||
ID: 111,
|
||||
Name: "name",
|
||||
CreatedAt: now,
|
||||
}, nil
|
||||
})
|
||||
},
|
||||
apiKey: uuid.NewString(),
|
||||
serverKey: "pl151",
|
||||
expectedStatus: http.StatusUnauthorized,
|
||||
target: &model.ErrorResp{},
|
||||
expectedResponse: &model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: "unauthorized",
|
||||
Message: "invalid API key",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
apiKeySvc := &mock.FakeAPIKeyVerifier{}
|
||||
sessionSvc := &mock.FakeSessionService{}
|
||||
tt.setup(apiKeySvc, sessionSvc)
|
||||
|
||||
router := rest.NewRouter(rest.RouterConfig{
|
||||
APIKeyVerifier: apiKeySvc,
|
||||
SessionService: sessionSvc,
|
||||
})
|
||||
|
||||
resp := doRequest(router, http.MethodGet, "/v1/user/sessions/"+tt.serverKey, tt.apiKey, nil)
|
||||
defer resp.Body.Close()
|
||||
assertJSONResponse(t, resp, tt.expectedStatus, tt.expectedResponse, tt.target)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,17 +9,17 @@ import (
|
|||
type userHandler struct {
|
||||
}
|
||||
|
||||
// @ID getAuthenticatedUser
|
||||
// @ID getCurrentUser
|
||||
// @Summary Get the authenticated user
|
||||
// @Description Get the authenticated user
|
||||
// @Tags users
|
||||
// @Produce json
|
||||
// @Success 200 {object} model.GetUserResp
|
||||
// @Success 401 {object} model.ErrorResp
|
||||
// @Failure 401 {object} model.ErrorResp
|
||||
// @Failure 500 {object} model.ErrorResp
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /user [get]
|
||||
func (h *userHandler) getAuthenticated(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *userHandler) getCurrent(w http.ResponseWriter, r *http.Request) {
|
||||
u, _ := userFromContext(r.Context())
|
||||
renderJSON(w, http.StatusOK, model.NewGetUserResp(u))
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
//counterfeiter:generate -o internal/mock/session_repository.gen.go . SessionRepository
|
||||
type SessionRepository interface {
|
||||
CreateOrUpdate(ctx context.Context, params domain.CreateSessionParams) (domain.Session, error)
|
||||
Get(ctx context.Context, userID int64, serverKey string) (domain.Session, error)
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
|
@ -37,3 +38,11 @@ func (s *Session) CreateOrUpdate(ctx context.Context, params domain.CreateSessio
|
|||
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
func (s *Session) Get(ctx context.Context, userID int64, serverKey string) (domain.Session, error) {
|
||||
sess, err := s.repo.Get(ctx, userID, serverKey)
|
||||
if err != nil {
|
||||
return domain.Session{}, fmt.Errorf("SessionRepository.Get: %w", err)
|
||||
}
|
||||
return sess, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue