Reviewed-on: #18
This commit is contained in:
parent
5f144a9fd2
commit
847ac51b38
|
@ -44,7 +44,8 @@ func newCreateAPIKeyCmd() *cli.Command {
|
|||
ctx, cancel := context.WithTimeout(c.Context, createAPIKeyTimeout)
|
||||
defer cancel()
|
||||
|
||||
ak, err := service.NewAPIKey(bundb.NewAPIKey(db), service.NewUser(bundb.NewUser(db))).Create(ctx, c.Int64("userId"))
|
||||
svc := service.NewAPIKey(bundb.NewAPIKey(db), service.NewUser(bundb.NewUser(db)))
|
||||
ak, err := svc.Create(ctx, c.String("name"), c.Int64("userId"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("APIKeyService.Create: %w", err)
|
||||
}
|
||||
|
@ -54,6 +55,10 @@ func newCreateAPIKeyCmd() *cli.Command {
|
|||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Required: true,
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "userId",
|
||||
Required: true,
|
||||
|
|
|
@ -24,12 +24,13 @@ func TestAPIKey_Create(t *testing.T) {
|
|||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params, err := domain.NewCreateAPIKeyParams(uuid.NewString(), fixture.user(t, "user-1").ID)
|
||||
params, err := domain.NewCreateAPIKeyParams(uuid.NewString(), uuid.NewString(), fixture.user(t, "user-1").ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
apiKey, err := repo.Create(context.Background(), params)
|
||||
assert.NoError(t, err)
|
||||
assert.Greater(t, apiKey.ID, int64(0))
|
||||
assert.Equal(t, params.Name(), apiKey.Name)
|
||||
assert.Equal(t, params.Key(), apiKey.Key)
|
||||
assert.Equal(t, params.UserID(), apiKey.UserID)
|
||||
assert.WithinDuration(t, time.Now(), apiKey.CreatedAt, time.Second)
|
||||
|
@ -38,7 +39,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+11111)
|
||||
params, err := domain.NewCreateAPIKeyParams(uuid.NewString(), uuid.NewString(), fixture.user(t, "user-1").ID+11111)
|
||||
require.NoError(t, err)
|
||||
|
||||
apiKey, err := repo.Create(context.Background(), params)
|
||||
|
@ -52,6 +53,7 @@ func TestAPIKey_Create(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
params, err := domain.NewCreateAPIKeyParams(
|
||||
uuid.NewString(),
|
||||
fixture.apiKey(t, "user-1-api-key-1").Key,
|
||||
fixture.user(t, "user-1").ID,
|
||||
)
|
||||
|
|
|
@ -11,6 +11,7 @@ type APIKey struct {
|
|||
bun.BaseModel `bun:"base_model,table:api_keys,alias:ak"`
|
||||
|
||||
ID int64 `bun:"id,pk,autoincrement,identity"`
|
||||
Name string `bun:"name,nullzero,type:varchar(100),notnull"`
|
||||
Key string `bun:"key,nullzero,type:varchar(255),notnull,unique"`
|
||||
UserID int64 `bun:"user_id,nullzero,notnull"`
|
||||
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
|
||||
|
@ -18,6 +19,7 @@ type APIKey struct {
|
|||
|
||||
func NewAPIKey(p domain.CreateAPIKeyParams) APIKey {
|
||||
return APIKey{
|
||||
Name: p.Name(),
|
||||
Key: p.Key(),
|
||||
UserID: p.UserID(),
|
||||
CreatedAt: time.Now(),
|
||||
|
@ -27,6 +29,7 @@ func NewAPIKey(p domain.CreateAPIKeyParams) APIKey {
|
|||
func (a APIKey) ToDomain() domain.APIKey {
|
||||
return domain.APIKey{
|
||||
ID: a.ID,
|
||||
Name: a.Name,
|
||||
Key: a.Key,
|
||||
UserID: a.UserID,
|
||||
CreatedAt: a.CreatedAt,
|
||||
|
|
|
@ -14,7 +14,7 @@ func TestAPIKey(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
var id int64 = 123
|
||||
params, err := domain.NewCreateAPIKeyParams(uuid.NewString(), 1)
|
||||
params, err := domain.NewCreateAPIKeyParams(uuid.NewString(), uuid.NewString(), 1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
result := model.NewAPIKey(params)
|
||||
|
@ -22,6 +22,7 @@ func TestAPIKey(t *testing.T) {
|
|||
|
||||
apiKey := result.ToDomain()
|
||||
assert.Equal(t, id, apiKey.ID)
|
||||
assert.Equal(t, params.Name(), apiKey.Name)
|
||||
assert.Equal(t, params.Key(), apiKey.Key)
|
||||
assert.Equal(t, params.UserID(), apiKey.UserID)
|
||||
assert.WithinDuration(t, time.Now(), apiKey.CreatedAt, 10*time.Millisecond)
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/bundb/internal/model"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
|
||||
return db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
|
||||
if _, err := tx.NewAddColumn().
|
||||
Model(&model.APIKey{}).
|
||||
ColumnExpr("name varchar(100)").
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return fmt.Errorf("api_keys - couldn't add the name column: %w", err)
|
||||
}
|
||||
|
||||
if _, err := tx.NewUpdate().
|
||||
Model(&model.APIKey{}).
|
||||
Set("name = ?", "api key").
|
||||
Where("true").
|
||||
Exec(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return fmt.Errorf("api_keys - name - couldn't set default value: %w", err)
|
||||
}
|
||||
|
||||
if _, err := tx.ExecContext(ctx, "ALTER TABLE api_keys ALTER COLUMN name SET NOT NULL"); err != nil {
|
||||
return fmt.Errorf("api_keys - name - couldn't set not null: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}, func(ctx context.Context, db *bun.DB) error {
|
||||
if _, err := db.NewDropColumn().
|
||||
Model(&model.APIKey{}).
|
||||
Column("name").
|
||||
Exec(ctx); err != nil {
|
||||
return fmt.Errorf("api_keys - couldn't drop the name column: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
rows:
|
||||
- _id: user-1-api-key-1
|
||||
id: 11111
|
||||
name: user-1-api-key-1
|
||||
key: 4c0d2d63-4ef7-4c23-bb4d-f3646cc9658f
|
||||
user_id: 11111
|
||||
created_at: 2022-03-15T15:15:10.000Z
|
||||
|
|
|
@ -5,19 +5,41 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
apiKeyMaxLength = 100
|
||||
)
|
||||
|
||||
type APIKey struct {
|
||||
ID int64
|
||||
Name string
|
||||
Key string
|
||||
UserID int64
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type CreateAPIKeyParams struct {
|
||||
name string
|
||||
key string
|
||||
userID int64
|
||||
}
|
||||
|
||||
func NewCreateAPIKeyParams(key string, userID int64) (CreateAPIKeyParams, error) {
|
||||
func NewCreateAPIKeyParams(name, key string, userID int64) (CreateAPIKeyParams, error) {
|
||||
if name == "" {
|
||||
return CreateAPIKeyParams{}, ValidationError{
|
||||
Field: "Name",
|
||||
Err: ErrRequired,
|
||||
}
|
||||
}
|
||||
|
||||
if len(name) > apiKeyMaxLength {
|
||||
return CreateAPIKeyParams{}, ValidationError{
|
||||
Field: "Name",
|
||||
Err: MaxLengthError{
|
||||
Max: apiKeyMaxLength,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if key == "" {
|
||||
return CreateAPIKeyParams{}, ValidationError{
|
||||
Field: "Key",
|
||||
|
@ -34,7 +56,11 @@ func NewCreateAPIKeyParams(key string, userID int64) (CreateAPIKeyParams, error)
|
|||
}
|
||||
}
|
||||
|
||||
return CreateAPIKeyParams{key: key, userID: userID}, nil
|
||||
return CreateAPIKeyParams{name: name, key: key, userID: userID}, nil
|
||||
}
|
||||
|
||||
func (c CreateAPIKeyParams) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c CreateAPIKeyParams) Key() string {
|
||||
|
|
|
@ -14,28 +14,52 @@ func TestNewCreateAPIKeyParams(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
name string
|
||||
keyName string
|
||||
key string
|
||||
userID int64
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
keyName: uuid.NewString(),
|
||||
key: uuid.NewString(),
|
||||
userID: 1,
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "ERR: username is required",
|
||||
key: "",
|
||||
name: "ERR: name is required",
|
||||
keyName: "",
|
||||
key: uuid.NewString(),
|
||||
expectedErr: domain.ValidationError{
|
||||
Field: "Name",
|
||||
Err: domain.ErrRequired,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: name is too long",
|
||||
keyName: randString(101),
|
||||
key: uuid.NewString(),
|
||||
expectedErr: domain.ValidationError{
|
||||
Field: "Name",
|
||||
Err: domain.MaxLengthError{
|
||||
Max: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: key is required",
|
||||
keyName: uuid.NewString(),
|
||||
key: "",
|
||||
expectedErr: domain.ValidationError{
|
||||
Field: "Key",
|
||||
Err: domain.ErrRequired,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: userID < 1",
|
||||
key: uuid.NewString(),
|
||||
userID: 0,
|
||||
name: "ERR: userID < 1",
|
||||
keyName: uuid.NewString(),
|
||||
key: uuid.NewString(),
|
||||
userID: 0,
|
||||
expectedErr: domain.ValidationError{
|
||||
Field: "UserID",
|
||||
Err: domain.MinError{
|
||||
|
@ -51,7 +75,7 @@ func TestNewCreateAPIKeyParams(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params, err := domain.NewCreateAPIKeyParams(tt.key, tt.userID)
|
||||
params, err := domain.NewCreateAPIKeyParams(tt.keyName, tt.key, tt.userID)
|
||||
if tt.expectedErr != nil {
|
||||
assert.Equal(t, tt.expectedErr, err)
|
||||
assert.Zero(t, params)
|
||||
|
|
|
@ -29,7 +29,7 @@ func NewAPIKey(repo APIKeyRepository, userSvc UserGetter) *APIKey {
|
|||
return &APIKey{repo: repo, userSvc: userSvc}
|
||||
}
|
||||
|
||||
func (a *APIKey) Create(ctx context.Context, userID int64) (domain.APIKey, error) {
|
||||
func (a *APIKey) Create(ctx context.Context, name string, userID int64) (domain.APIKey, error) {
|
||||
user, err := a.userSvc.Get(ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, domain.UserNotFoundError{ID: userID}) {
|
||||
|
@ -43,7 +43,7 @@ func (a *APIKey) Create(ctx context.Context, userID int64) (domain.APIKey, error
|
|||
return domain.APIKey{}, fmt.Errorf("couldn't generate api key: %w", err)
|
||||
}
|
||||
|
||||
params, err := domain.NewCreateAPIKeyParams(key.String(), user.ID)
|
||||
params, err := domain.NewCreateAPIKeyParams(name, key.String(), user.ID)
|
||||
if err != nil {
|
||||
return domain.APIKey{}, err
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ func TestAPIKey_Create(t *testing.T) {
|
|||
apiKeyRepo.CreateCalls(func(ctx context.Context, params domain.CreateAPIKeyParams) (domain.APIKey, error) {
|
||||
return domain.APIKey{
|
||||
ID: 1,
|
||||
Name: params.Name(),
|
||||
Key: params.Key(),
|
||||
UserID: params.UserID(),
|
||||
CreatedAt: time.Now(),
|
||||
|
@ -32,9 +33,11 @@ func TestAPIKey_Create(t *testing.T) {
|
|||
user := domain.User{ID: 1234}
|
||||
userSvc.GetReturns(user, nil)
|
||||
|
||||
ak, err := service.NewAPIKey(apiKeyRepo, userSvc).Create(context.Background(), user.ID)
|
||||
name := uuid.NewString()
|
||||
ak, err := service.NewAPIKey(apiKeyRepo, userSvc).Create(context.Background(), name, user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Greater(t, ak.ID, int64(0))
|
||||
assert.Equal(t, name, ak.Name)
|
||||
_, err = uuid.Parse(ak.Key)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, user.ID, ak.UserID)
|
||||
|
@ -48,7 +51,7 @@ func TestAPIKey_Create(t *testing.T) {
|
|||
var userID int64 = 1234
|
||||
userSvc.GetReturns(domain.User{}, domain.UserNotFoundError{ID: userID})
|
||||
|
||||
ak, err := service.NewAPIKey(nil, userSvc).Create(context.Background(), userID)
|
||||
ak, err := service.NewAPIKey(nil, userSvc).Create(context.Background(), uuid.NewString(), userID)
|
||||
assert.ErrorIs(t, err, domain.UserDoesNotExistError{ID: userID})
|
||||
assert.Zero(t, ak)
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue