feat: session name (#18)
continuous-integration/drone/push Build is passing Details

Reviewed-on: #18
This commit is contained in:
Dawid Wysokiński 2022-12-02 05:29:11 +00:00
parent 5f144a9fd2
commit 847ac51b38
10 changed files with 128 additions and 16 deletions

View File

@ -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,

View File

@ -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,
)

View File

@ -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,

View File

@ -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)

View File

@ -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
})
}

View File

@ -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

View File

@ -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 {

View File

@ -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)

View File

@ -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
}

View File

@ -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)
})