diff options
author | Gabriel Arakaki Giovanini <mail@gabrielgio.me> | 2023-06-29 23:05:23 +0200 |
---|---|---|
committer | Gabriel Arakaki Giovanini <mail@gabrielgio.me> | 2023-06-29 23:06:44 +0200 |
commit | 024da3e546e98cbaeea5f7bc86af12b671996f41 (patch) | |
tree | 08b38491b7e726fb448cceaceb2ef536360b2223 | |
parent | 9ba53fea71728ce64342d0d59f4199876e4b6164 (diff) | |
download | lens-024da3e546e98cbaeea5f7bc86af12b671996f41.tar.gz lens-024da3e546e98cbaeea5f7bc86af12b671996f41.tar.bz2 lens-024da3e546e98cbaeea5f7bc86af12b671996f41.zip |
ref: Refactor how repository is define
To make things easier and reduce the number of package I'll move all
repository to one folder, starting with auth and user repository.
Also implements all testing on top of the repository interface with a im
memory implementation. This will later make mescling unit and
integration easier.
-rw-r--r-- | pkg/components/auth/controller.go | 18 | ||||
-rw-r--r-- | pkg/components/auth/controller_test.go | 162 | ||||
-rw-r--r-- | pkg/components/auth/mock_test.go | 121 | ||||
-rw-r--r-- | pkg/database/repository/auth.go (renamed from pkg/components/auth/model.go) | 4 | ||||
-rw-r--r-- | pkg/database/repository/user.go (renamed from pkg/components/user/model.go) | 7 | ||||
-rw-r--r-- | pkg/database/sql/user.go | 23 | ||||
-rw-r--r-- | pkg/ext/middleware.go | 6 | ||||
-rw-r--r-- | pkg/testkit/testkit.go | 3 | ||||
-rw-r--r-- | pkg/view/media.go | 2 | ||||
-rw-r--r-- | pkg/view/settings.go | 8 |
10 files changed, 171 insertions, 183 deletions
diff --git a/pkg/components/auth/controller.go b/pkg/components/auth/controller.go index a33d9b3..0b08fcc 100644 --- a/pkg/components/auth/controller.go +++ b/pkg/components/auth/controller.go @@ -6,35 +6,35 @@ import ( "golang.org/x/crypto/bcrypt" "git.sr.ht/~gabrielgio/img/pkg/components" - "git.sr.ht/~gabrielgio/img/pkg/components/user" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/ext" ) type Controller struct { - repository Repository - userRepository user.Repository + authRepository repository.AuthRepository + userRepository repository.UserRepository key []byte } func NewController( - repository Repository, - userRepository user.Repository, + authRepository repository.AuthRepository, + userRepository repository.UserRepository, key []byte, ) *Controller { return &Controller{ - repository: repository, + authRepository: authRepository, userRepository: userRepository, key: key, } } func (c *Controller) Login(ctx context.Context, username, password []byte) ([]byte, error) { - id, err := c.repository.GetIDByUsername(ctx, string(username)) + id, err := c.authRepository.GetIDByUsername(ctx, string(username)) if err != nil { return nil, err } - hashedPassword, err := c.repository.GetPassword(ctx, id) + hashedPassword, err := c.authRepository.GetPassword(ctx, id) if err != nil { return nil, err } @@ -67,7 +67,7 @@ func (c *Controller) InitialRegister(ctx context.Context, username, password []b return err } - _, err = c.userRepository.Create(ctx, &user.CreateUser{ + _, err = c.userRepository.Create(ctx, &repository.CreateUser{ Username: string(username), Password: hash, Path: string(path), diff --git a/pkg/components/auth/controller_test.go b/pkg/components/auth/controller_test.go index 50bf69b..b1ca065 100644 --- a/pkg/components/auth/controller_test.go +++ b/pkg/components/auth/controller_test.go @@ -4,12 +4,9 @@ package auth import ( "context" - "errors" "testing" - "github.com/samber/lo" - - "git.sr.ht/~gabrielgio/img/pkg/components/user" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/ext" "git.sr.ht/~gabrielgio/img/pkg/testkit" ) @@ -17,41 +14,23 @@ import ( type ( scene struct { ctx context.Context - mockRepository *MockAuthRepository - controller Controller - } - - mockUser struct { - id uint - username string - password []byte - } - - MockAuthRepository struct { - index uint - users []*mockUser - err error - } - - MockUserRepository struct { - index uint - users []*mockUser - err error + authRepository repository.AuthRepository + userRepository repository.UserRepository + controller *Controller } ) var ( - _ Repository = &MockAuthRepository{} - key = []byte("6368616e676520746869732070617373") + key = []byte("6368616e676520746869732070617373") ) func setUp() *scene { - mockAuthRepository := &MockAuthRepository{} - mockUserRepository := &MockUserRepository{} + userRepository := NewUserRepository() return &scene{ ctx: context.Background(), - mockRepository: mockAuthRepository, - controller: *NewController(mockAuthRepository, mockUserRepository, key), + authRepository: userRepository, + userRepository: userRepository, + controller: NewController(userRepository, userRepository, key), } } @@ -64,7 +43,7 @@ func TestInitialRegisterAndLogin(t *testing.T) { { name: "Normal register", username: "username", - password: []byte("password"), + password: []byte("this is an password"), }, } @@ -75,9 +54,10 @@ func TestInitialRegisterAndLogin(t *testing.T) { err := scene.controller.InitialRegister(scene.ctx, []byte(tc.username), tc.password, []byte("/")) testkit.TestFatalError(t, "Register", err) - userID := scene.mockRepository.GetLastId() + users, err := scene.userRepository.List(scene.ctx) + userID := users[0].ID - user, err := scene.mockRepository.Get(scene.ctx, userID) + user, err := scene.userRepository.Get(scene.ctx, userID) testkit.TestFatalError(t, "Get", err) testkit.TestValue(t, "Register", tc.username, user.Username) @@ -93,122 +73,6 @@ func TestInitialRegisterAndLogin(t *testing.T) { } } -func toUser(m *mockUser, _ int) *user.User { - return &user.User{ - ID: m.id, - Username: m.username, - } -} - -func (m *MockAuthRepository) GetLastId() uint { - return m.index -} - -func (m *MockAuthRepository) List(ctx context.Context) ([]*user.User, error) { - if m.err != nil { - return nil, m.err - } - - return lo.Map(m.users, toUser), nil -} - -func (m *MockAuthRepository) Get(ctx context.Context, id uint) (*user.User, error) { - if m.err != nil { - return nil, m.err - } - - for _, m := range m.users { - if m.id == id { - return toUser(m, 0), nil - } - } - return nil, errors.New("Item not found") -} - -func (m *MockAuthRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) { - if m.err != nil { - return 0, m.err - } - - for _, m := range m.users { - if m.username == username { - return m.id, nil - } - } - return 0, errors.New("Item not found") -} - -func (m *MockAuthRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) { - if m.err != nil { - return nil, m.err - } - - for _, m := range m.users { - if m.id == id { - return m.password, nil - } - } - return nil, errors.New("Item not found") -} - -func (m *MockAuthRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) { - if m.err != nil { - return 0, m.err - } - - m.index++ - - m.users = append(m.users, &mockUser{ - id: m.index, - username: createUser.Username, - password: createUser.Password, - }) - - return m.index, nil -} - -func (m *MockAuthRepository) Update(ctx context.Context, id uint, update *user.UpdateUser) error { - if m.err != nil { - return m.err - } - - for _, m := range m.users { - if m.id == id { - m.username = update.Username - } - } - return nil -} - func remove[T any](slice []T, s int) []T { return append(slice[:s], slice[s+1:]...) } - -func (r *MockAuthRepository) Delete(ctx context.Context, id uint) error { - if r.err != nil { - return r.err - } - - for i, m := range r.users { - if m.id == id { - r.users = remove(r.users, i) - } - } - return nil -} - -func (m *MockUserRepository) List(ctx context.Context) ([]*user.User, error) { - panic("not implemented") // TODO: Implement -} - -func (m *MockUserRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) { - panic("not implemented") // TODO: Implement -} - -func (m *MockUserRepository) Update(ctx context.Context, id uint, updateUser *user.UpdateUser) error { - panic("not implemented") // TODO: Implement -} - -func (m *MockUserRepository) Any(ctx context.Context) (bool, error) { - panic("not implemented") // TODO: Implement -} diff --git a/pkg/components/auth/mock_test.go b/pkg/components/auth/mock_test.go new file mode 100644 index 0000000..885f643 --- /dev/null +++ b/pkg/components/auth/mock_test.go @@ -0,0 +1,121 @@ +//go:build unit + +package auth + +import ( + "context" + "errors" + + "git.sr.ht/~gabrielgio/img/pkg/database/repository" +) + +type ( + User struct { + ID uint + Username string + Name string + Password []byte + IsAdmin bool + Path string + } + + Users map[uint]*User + + UserRepository struct { + icount uint + users Users + } +) + +var _ repository.UserRepository = &UserRepository{} +var _ repository.AuthRepository = &UserRepository{} + +func NewUserRepository() *UserRepository { + return &UserRepository{ + users: make(map[uint]*User), + } +} + +func (u *User) ToModel() *repository.User { + return &repository.User{ + ID: u.ID, + Username: u.Username, + Name: u.Name, + IsAdmin: u.IsAdmin, + Path: u.Path, + } +} + +func (u Users) ToModels() []*repository.User { + users := make([]*repository.User, 0, len(u)) + for _, i := range u { + users = append(users, i.ToModel()) + } + return users +} + +func (u *UserRepository) Get(ctx context.Context, id uint) (*repository.User, error) { + if user, ok := u.users[id]; ok { + return user.ToModel(), nil + } + + return nil, errors.New("Not Found") +} + +func (u *UserRepository) List(_ context.Context) ([]*repository.User, error) { + return u.users.ToModels(), nil +} + +func (u *UserRepository) Create(_ context.Context, createUser *repository.CreateUser) (uint, error) { + id := u.furtherID() + u.users[id] = &User{ + ID: id, + Name: createUser.Name, + Username: createUser.Username, + Path: createUser.Path, + Password: createUser.Password, + } + return id, nil +} + +func (u *UserRepository) Update(_ context.Context, id uint, updateUser *repository.UpdateUser) error { + user, ok := u.users[id] + if !ok { + return errors.New("Invalid ID") + } + + user.Name = updateUser.Name + user.Username = updateUser.Username + if updateUser.Password != "" { + user.Password = []byte(updateUser.Password) + } + + return nil +} + +func (u *UserRepository) Any(_ context.Context) (bool, error) { + return len(u.users) > 0, nil +} + +func (u *UserRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) { + for id, u := range u.users { + if u.Username == username { + return id, nil + } + } + + return 0, errors.New("Not Found") +} + +func (u *UserRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) { + if user, ok := u.users[id]; ok { + return []byte(user.Password), nil + } + + return nil, errors.New("Not Found") +} + +func (u *UserRepository) furtherID() uint { + u.icount++ + return u.icount +} diff --git a/pkg/components/auth/model.go b/pkg/database/repository/auth.go index dd6ce50..b319495 100644 --- a/pkg/components/auth/model.go +++ b/pkg/database/repository/auth.go @@ -1,9 +1,9 @@ -package auth +package repository import "context" type ( - Repository interface { + AuthRepository interface { GetIDByUsername(ctx context.Context, username string) (uint, error) GetPassword(ctx context.Context, id uint) ([]byte, error) } diff --git a/pkg/components/user/model.go b/pkg/database/repository/user.go index 0ff6d0a..f8bd719 100644 --- a/pkg/components/user/model.go +++ b/pkg/database/repository/user.go @@ -1,4 +1,4 @@ -package user +package repository import "context" @@ -14,7 +14,7 @@ type ( UpdateUser struct { Username string Name string - Password *string + Password string } CreateUser struct { @@ -25,7 +25,8 @@ type ( Path string } - Repository interface { + UserRepository interface { + Get(ctx context.Context, id uint) (*User, error) List(ctx context.Context) ([]*User, error) Create(ctx context.Context, createUser *CreateUser) (uint, error) Update(ctx context.Context, id uint, updateUser *UpdateUser) error diff --git a/pkg/database/sql/user.go b/pkg/database/sql/user.go index a0884f4..479a9c5 100644 --- a/pkg/database/sql/user.go +++ b/pkg/database/sql/user.go @@ -6,8 +6,7 @@ import ( "golang.org/x/crypto/bcrypt" "gorm.io/gorm" - "git.sr.ht/~gabrielgio/img/pkg/components/auth" - "git.sr.ht/~gabrielgio/img/pkg/components/user" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" ) type ( @@ -27,8 +26,8 @@ type ( } ) -var _ auth.Repository = &UserRepository{} -var _ user.Repository = &UserRepository{} +var _ repository.UserRepository = &UserRepository{} +var _ repository.AuthRepository = &UserRepository{} func NewUserRepository(db *gorm.DB) *UserRepository { return &UserRepository{ @@ -36,8 +35,8 @@ func NewUserRepository(db *gorm.DB) *UserRepository { } } -func (self *User) ToModel() *user.User { - return &user.User{ +func (self *User) ToModel() *repository.User { + return &repository.User{ ID: self.Model.ID, Name: self.Name, Username: self.Username, @@ -46,7 +45,7 @@ func (self *User) ToModel() *user.User { } } -func (self Users) ToModel() (users []*user.User) { +func (self Users) ToModel() (users []*repository.User) { for _, user := range self { users = append(users, user.ToModel()) } @@ -75,7 +74,7 @@ func (self *UserRepository) EnsureAdmin(ctx context.Context) { } } -func (self *UserRepository) List(ctx context.Context) ([]*user.User, error) { +func (self *UserRepository) List(ctx context.Context) ([]*repository.User, error) { users := Users{} result := self.db. WithContext(ctx). @@ -88,8 +87,8 @@ func (self *UserRepository) List(ctx context.Context) ([]*user.User, error) { return users.ToModel(), nil } -func (self *UserRepository) Get(ctx context.Context, id uint) (*user.User, error) { - var user = &user.User{ID: id} +func (self *UserRepository) Get(ctx context.Context, id uint) (*repository.User, error) { + var user = &repository.User{ID: id} result := self.db. WithContext(ctx). First(user) @@ -137,7 +136,7 @@ func (self *UserRepository) GetPassword(ctx context.Context, id uint) ([]byte, e return userPassword.Password, nil } -func (self *UserRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) { +func (self *UserRepository) Create(ctx context.Context, createUser *repository.CreateUser) (uint, error) { user := &User{ Username: createUser.Username, Name: createUser.Name, @@ -154,7 +153,7 @@ func (self *UserRepository) Create(ctx context.Context, createUser *user.CreateU return user.Model.ID, nil } -func (self *UserRepository) Update(ctx context.Context, id uint, update *user.UpdateUser) error { +func (self *UserRepository) Update(ctx context.Context, id uint, update *repository.UpdateUser) error { user := &User{ Model: gorm.Model{ ID: id, diff --git a/pkg/ext/middleware.go b/pkg/ext/middleware.go index bc23b90..d255c6d 100644 --- a/pkg/ext/middleware.go +++ b/pkg/ext/middleware.go @@ -7,7 +7,7 @@ import ( "github.com/sirupsen/logrus" "github.com/valyala/fasthttp" - "git.sr.ht/~gabrielgio/img/pkg/components/user" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" ) func HTML(next fasthttp.RequestHandler) fasthttp.RequestHandler { @@ -91,10 +91,10 @@ func (a *AuthMiddleware) LoggedIn(next fasthttp.RequestHandler) fasthttp.Request } type InitialSetupMiddleware struct { - userRepository user.Repository + userRepository repository.UserRepository } -func NewInitialSetupMiddleware(userRepository user.Repository) *InitialSetupMiddleware { +func NewInitialSetupMiddleware(userRepository repository.UserRepository) *InitialSetupMiddleware { return &InitialSetupMiddleware{ userRepository: userRepository, } diff --git a/pkg/testkit/testkit.go b/pkg/testkit/testkit.go index 526e1b3..3cc4afd 100644 --- a/pkg/testkit/testkit.go +++ b/pkg/testkit/testkit.go @@ -9,18 +9,21 @@ import ( ) func TestValue[T any](t *testing.T, method string, want, got T) { + t.Helper() if diff := cmp.Diff(want, got); diff != "" { t.Errorf("%s() mismatch (-want +got):\n%s", method, diff) } } func TestFatalError(t *testing.T, method string, err error) { + t.Helper() if err != nil { t.Fatalf("%s() fatal error : %+v", method, err) } } func TestError(t *testing.T, method string, want, got error) { + t.Helper() if !equalError(want, got) { t.Errorf("%s() err mismatch want: %+v got %+v", method, want, got) } diff --git a/pkg/view/media.go b/pkg/view/media.go index 22f950d..66e3020 100644 --- a/pkg/view/media.go +++ b/pkg/view/media.go @@ -89,7 +89,7 @@ func (self *MediaView) GetImage(ctx *fasthttp.RequestCtx) error { } ctx.Response.Header.SetContentType(media.MIMEType) - ctx.SendFile(media.Path) + fasthttp.ServeFileUncompressed(ctx, media.Path) return nil } diff --git a/pkg/view/settings.go b/pkg/view/settings.go index e5acb1b..954cc98 100644 --- a/pkg/view/settings.go +++ b/pkg/view/settings.go @@ -5,7 +5,7 @@ import ( "git.sr.ht/~gabrielgio/img" "git.sr.ht/~gabrielgio/img/pkg/components/settings" - "git.sr.ht/~gabrielgio/img/pkg/components/user" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/ext" ) @@ -13,18 +13,18 @@ type ( SettingsView struct { // there is not need to create a controller for this settingsRepository settings.Repository - userRepository user.Repository + userRepository repository.UserRepository } SettingsPage struct { Settings *settings.Settings - Users []*user.User + Users []*repository.User } ) func NewSettingsView( settingsRespository settings.Repository, - userRepository user.Repository, + userRepository repository.UserRepository, ) *SettingsView { return &SettingsView{ settingsRepository: settingsRespository, |