1diff --git a/pkg/components/auth/controller.go b/pkg/components/auth/controller.go
2index a33d9b37458ee677835aff5a26543fe84a3ac6c6..0b08fccedac11e0cc5970a746e46432b2390134f 100644
3--- a/pkg/components/auth/controller.go
4+++ b/pkg/components/auth/controller.go
5@@ -6,35 +6,35 @@
6 "golang.org/x/crypto/bcrypt"
7
8 "git.sr.ht/~gabrielgio/img/pkg/components"
9- "git.sr.ht/~gabrielgio/img/pkg/components/user"
10+ "git.sr.ht/~gabrielgio/img/pkg/database/repository"
11 "git.sr.ht/~gabrielgio/img/pkg/ext"
12 )
13
14 type Controller struct {
15- repository Repository
16- userRepository user.Repository
17+ authRepository repository.AuthRepository
18+ userRepository repository.UserRepository
19 key []byte
20 }
21
22 func NewController(
23- repository Repository,
24- userRepository user.Repository,
25+ authRepository repository.AuthRepository,
26+ userRepository repository.UserRepository,
27 key []byte,
28 ) *Controller {
29 return &Controller{
30- repository: repository,
31+ authRepository: authRepository,
32 userRepository: userRepository,
33 key: key,
34 }
35 }
36
37 func (c *Controller) Login(ctx context.Context, username, password []byte) ([]byte, error) {
38- id, err := c.repository.GetIDByUsername(ctx, string(username))
39+ id, err := c.authRepository.GetIDByUsername(ctx, string(username))
40 if err != nil {
41 return nil, err
42 }
43
44- hashedPassword, err := c.repository.GetPassword(ctx, id)
45+ hashedPassword, err := c.authRepository.GetPassword(ctx, id)
46 if err != nil {
47 return nil, err
48 }
49@@ -67,7 +67,7 @@ if err != nil {
50 return err
51 }
52
53- _, err = c.userRepository.Create(ctx, &user.CreateUser{
54+ _, err = c.userRepository.Create(ctx, &repository.CreateUser{
55 Username: string(username),
56 Password: hash,
57 Path: string(path),
58diff --git a/pkg/components/auth/controller_test.go b/pkg/components/auth/controller_test.go
59index 50bf69b08d8dea4e8d4d5e3dbf4e706701984139..b1ca065d481107931ccca4ee3cc48d581472c5f5 100644
60--- a/pkg/components/auth/controller_test.go
61+++ b/pkg/components/auth/controller_test.go
62@@ -4,12 +4,9 @@ package auth
63
64 import (
65 "context"
66- "errors"
67 "testing"
68
69- "github.com/samber/lo"
70-
71- "git.sr.ht/~gabrielgio/img/pkg/components/user"
72+ "git.sr.ht/~gabrielgio/img/pkg/database/repository"
73 "git.sr.ht/~gabrielgio/img/pkg/ext"
74 "git.sr.ht/~gabrielgio/img/pkg/testkit"
75 )
76@@ -17,41 +14,23 @@
77 type (
78 scene struct {
79 ctx context.Context
80- mockRepository *MockAuthRepository
81- controller Controller
82- }
83-
84- mockUser struct {
85- id uint
86- username string
87- password []byte
88- }
89-
90- MockAuthRepository struct {
91- index uint
92- users []*mockUser
93- err error
94- }
95-
96- MockUserRepository struct {
97- index uint
98- users []*mockUser
99- err error
100+ authRepository repository.AuthRepository
101+ userRepository repository.UserRepository
102+ controller *Controller
103 }
104 )
105
106 var (
107- _ Repository = &MockAuthRepository{}
108- key = []byte("6368616e676520746869732070617373")
109+ key = []byte("6368616e676520746869732070617373")
110 )
111
112 func setUp() *scene {
113- mockAuthRepository := &MockAuthRepository{}
114- mockUserRepository := &MockUserRepository{}
115+ userRepository := NewUserRepository()
116 return &scene{
117 ctx: context.Background(),
118- mockRepository: mockAuthRepository,
119- controller: *NewController(mockAuthRepository, mockUserRepository, key),
120+ authRepository: userRepository,
121+ userRepository: userRepository,
122+ controller: NewController(userRepository, userRepository, key),
123 }
124 }
125
126@@ -64,7 +43,7 @@ }{
127 {
128 name: "Normal register",
129 username: "username",
130- password: []byte("password"),
131+ password: []byte("this is an password"),
132 },
133 }
134
135@@ -75,9 +54,10 @@
136 err := scene.controller.InitialRegister(scene.ctx, []byte(tc.username), tc.password, []byte("/"))
137 testkit.TestFatalError(t, "Register", err)
138
139- userID := scene.mockRepository.GetLastId()
140+ users, err := scene.userRepository.List(scene.ctx)
141+ userID := users[0].ID
142
143- user, err := scene.mockRepository.Get(scene.ctx, userID)
144+ user, err := scene.userRepository.Get(scene.ctx, userID)
145 testkit.TestFatalError(t, "Get", err)
146 testkit.TestValue(t, "Register", tc.username, user.Username)
147
148@@ -93,122 +73,6 @@ })
149 }
150 }
151
152-func toUser(m *mockUser, _ int) *user.User {
153- return &user.User{
154- ID: m.id,
155- Username: m.username,
156- }
157-}
158-
159-func (m *MockAuthRepository) GetLastId() uint {
160- return m.index
161-}
162-
163-func (m *MockAuthRepository) List(ctx context.Context) ([]*user.User, error) {
164- if m.err != nil {
165- return nil, m.err
166- }
167-
168- return lo.Map(m.users, toUser), nil
169-}
170-
171-func (m *MockAuthRepository) Get(ctx context.Context, id uint) (*user.User, error) {
172- if m.err != nil {
173- return nil, m.err
174- }
175-
176- for _, m := range m.users {
177- if m.id == id {
178- return toUser(m, 0), nil
179- }
180- }
181- return nil, errors.New("Item not found")
182-}
183-
184-func (m *MockAuthRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) {
185- if m.err != nil {
186- return 0, m.err
187- }
188-
189- for _, m := range m.users {
190- if m.username == username {
191- return m.id, nil
192- }
193- }
194- return 0, errors.New("Item not found")
195-}
196-
197-func (m *MockAuthRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) {
198- if m.err != nil {
199- return nil, m.err
200- }
201-
202- for _, m := range m.users {
203- if m.id == id {
204- return m.password, nil
205- }
206- }
207- return nil, errors.New("Item not found")
208-}
209-
210-func (m *MockAuthRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) {
211- if m.err != nil {
212- return 0, m.err
213- }
214-
215- m.index++
216-
217- m.users = append(m.users, &mockUser{
218- id: m.index,
219- username: createUser.Username,
220- password: createUser.Password,
221- })
222-
223- return m.index, nil
224-}
225-
226-func (m *MockAuthRepository) Update(ctx context.Context, id uint, update *user.UpdateUser) error {
227- if m.err != nil {
228- return m.err
229- }
230-
231- for _, m := range m.users {
232- if m.id == id {
233- m.username = update.Username
234- }
235- }
236- return nil
237-}
238-
239 func remove[T any](slice []T, s int) []T {
240 return append(slice[:s], slice[s+1:]...)
241 }
242-
243-func (r *MockAuthRepository) Delete(ctx context.Context, id uint) error {
244- if r.err != nil {
245- return r.err
246- }
247-
248- for i, m := range r.users {
249- if m.id == id {
250- r.users = remove(r.users, i)
251- }
252- }
253- return nil
254-}
255-
256-func (m *MockUserRepository) List(ctx context.Context) ([]*user.User, error) {
257- panic("not implemented") // TODO: Implement
258-}
259-
260-func (m *MockUserRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) {
261- panic("not implemented") // TODO: Implement
262-}
263-
264-func (m *MockUserRepository) Update(ctx context.Context, id uint, updateUser *user.UpdateUser) error {
265- panic("not implemented") // TODO: Implement
266-}
267-
268-func (m *MockUserRepository) Any(ctx context.Context) (bool, error) {
269- panic("not implemented") // TODO: Implement
270-}
271diff --git a/pkg/components/auth/mock_test.go b/pkg/components/auth/mock_test.go
272new file mode 100644
273index 0000000000000000000000000000000000000000..885f64316d474bdf213965a55660ee94fd6bd5b2
274--- /dev/null
275+++ b/pkg/components/auth/mock_test.go
276@@ -0,0 +1,121 @@
277+//go:build unit
278+
279+package auth
280+
281+import (
282+ "context"
283+ "errors"
284+
285+ "git.sr.ht/~gabrielgio/img/pkg/database/repository"
286+)
287+
288+type (
289+ User struct {
290+ ID uint
291+ Username string
292+ Name string
293+ Password []byte
294+ IsAdmin bool
295+ Path string
296+ }
297+
298+ Users map[uint]*User
299+
300+ UserRepository struct {
301+ icount uint
302+ users Users
303+ }
304+)
305+
306+var _ repository.UserRepository = &UserRepository{}
307+var _ repository.AuthRepository = &UserRepository{}
308+
309+func NewUserRepository() *UserRepository {
310+ return &UserRepository{
311+ users: make(map[uint]*User),
312+ }
313+}
314+
315+func (u *User) ToModel() *repository.User {
316+ return &repository.User{
317+ ID: u.ID,
318+ Username: u.Username,
319+ Name: u.Name,
320+ IsAdmin: u.IsAdmin,
321+ Path: u.Path,
322+ }
323+}
324+
325+func (u Users) ToModels() []*repository.User {
326+ users := make([]*repository.User, 0, len(u))
327+ for _, i := range u {
328+ users = append(users, i.ToModel())
329+ }
330+ return users
331+}
332+
333+func (u *UserRepository) Get(ctx context.Context, id uint) (*repository.User, error) {
334+ if user, ok := u.users[id]; ok {
335+ return user.ToModel(), nil
336+ }
337+
338+ return nil, errors.New("Not Found")
339+}
340+
341+func (u *UserRepository) List(_ context.Context) ([]*repository.User, error) {
342+ return u.users.ToModels(), nil
343+}
344+
345+func (u *UserRepository) Create(_ context.Context, createUser *repository.CreateUser) (uint, error) {
346+ id := u.furtherID()
347+ u.users[id] = &User{
348+ ID: id,
349+ Name: createUser.Name,
350+ Username: createUser.Username,
351+ Path: createUser.Path,
352+ Password: createUser.Password,
353+ }
354+ return id, nil
355+}
356+
357+func (u *UserRepository) Update(_ context.Context, id uint, updateUser *repository.UpdateUser) error {
358+ user, ok := u.users[id]
359+ if !ok {
360+ return errors.New("Invalid ID")
361+ }
362+
363+ user.Name = updateUser.Name
364+ user.Username = updateUser.Username
365+ if updateUser.Password != "" {
366+ user.Password = []byte(updateUser.Password)
367+ }
368+
369+ return nil
370+}
371+
372+func (u *UserRepository) Any(_ context.Context) (bool, error) {
373+ return len(u.users) > 0, nil
374+}
375+
376+func (u *UserRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) {
377+ for id, u := range u.users {
378+ if u.Username == username {
379+ return id, nil
380+ }
381+ }
382+
383+ return 0, errors.New("Not Found")
384+}
385+
386+func (u *UserRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) {
387+ if user, ok := u.users[id]; ok {
388+ return []byte(user.Password), nil
389+ }
390+
391+ return nil, errors.New("Not Found")
392+}
393+
394+func (u *UserRepository) furtherID() uint {
395+ u.icount++
396+ return u.icount
397+}
398diff --git a/pkg/components/auth/model.go b/pkg/database/repository/auth.go
399rename from pkg/components/auth/model.go
400rename to pkg/database/repository/auth.go
401index dd6ce5036b91127e13e37c4e57b7baa13b486a1a..b3194956c9c9b0dcefda0d4cc64c297f900479f8 100644
402--- a/pkg/components/auth/model.go
403+++ b/pkg/database/repository/auth.go
404@@ -1,9 +1,9 @@
405-package auth
406+package repository
407
408 import "context"
409
410 type (
411- Repository interface {
412+ AuthRepository interface {
413 GetIDByUsername(ctx context.Context, username string) (uint, error)
414 GetPassword(ctx context.Context, id uint) ([]byte, error)
415 }
416diff --git a/pkg/components/user/model.go b/pkg/database/repository/user.go
417rename from pkg/components/user/model.go
418rename to pkg/database/repository/user.go
419index 0ff6d0ab9a5b77cbfef5fab9f5b717d6e066119e..f8bd71921567ddf5ed5bdd3ed15e4e526f3bad64 100644
420--- a/pkg/components/user/model.go
421+++ b/pkg/database/repository/user.go
422@@ -1,4 +1,4 @@
423-package user
424+package repository
425
426 import "context"
427
428@@ -14,7 +14,7 @@
429 UpdateUser struct {
430 Username string
431 Name string
432- Password *string
433+ Password string
434 }
435
436 CreateUser struct {
437@@ -25,7 +25,8 @@ IsAdmin bool
438 Path string
439 }
440
441- Repository interface {
442+ UserRepository interface {
443+ Get(ctx context.Context, id uint) (*User, error)
444 List(ctx context.Context) ([]*User, error)
445 Create(ctx context.Context, createUser *CreateUser) (uint, error)
446 Update(ctx context.Context, id uint, updateUser *UpdateUser) error
447diff --git a/pkg/database/sql/user.go b/pkg/database/sql/user.go
448index a0884f4f6e1db95c98c490fbb6ca6e10ac214de4..479a9c59d36cb407f4693b663c409eb71701ee6b 100644
449--- a/pkg/database/sql/user.go
450+++ b/pkg/database/sql/user.go
451@@ -6,8 +6,7 @@
452 "golang.org/x/crypto/bcrypt"
453 "gorm.io/gorm"
454
455- "git.sr.ht/~gabrielgio/img/pkg/components/auth"
456- "git.sr.ht/~gabrielgio/img/pkg/components/user"
457+ "git.sr.ht/~gabrielgio/img/pkg/database/repository"
458 )
459
460 type (
461@@ -27,8 +26,8 @@ db *gorm.DB
462 }
463 )
464
465-var _ auth.Repository = &UserRepository{}
466-var _ user.Repository = &UserRepository{}
467+var _ repository.UserRepository = &UserRepository{}
468+var _ repository.AuthRepository = &UserRepository{}
469
470 func NewUserRepository(db *gorm.DB) *UserRepository {
471 return &UserRepository{
472@@ -36,8 +35,8 @@ db: db,
473 }
474 }
475
476-func (self *User) ToModel() *user.User {
477- return &user.User{
478+func (self *User) ToModel() *repository.User {
479+ return &repository.User{
480 ID: self.Model.ID,
481 Name: self.Name,
482 Username: self.Username,
483@@ -46,7 +45,7 @@ IsAdmin: self.IsAdmin,
484 }
485 }
486
487-func (self Users) ToModel() (users []*user.User) {
488+func (self Users) ToModel() (users []*repository.User) {
489 for _, user := range self {
490 users = append(users, user.ToModel())
491 }
492@@ -75,7 +74,7 @@ })
493 }
494 }
495
496-func (self *UserRepository) List(ctx context.Context) ([]*user.User, error) {
497+func (self *UserRepository) List(ctx context.Context) ([]*repository.User, error) {
498 users := Users{}
499 result := self.db.
500 WithContext(ctx).
501@@ -88,8 +87,8 @@
502 return users.ToModel(), nil
503 }
504
505-func (self *UserRepository) Get(ctx context.Context, id uint) (*user.User, error) {
506- var user = &user.User{ID: id}
507+func (self *UserRepository) Get(ctx context.Context, id uint) (*repository.User, error) {
508+ var user = &repository.User{ID: id}
509 result := self.db.
510 WithContext(ctx).
511 First(user)
512@@ -137,7 +136,7 @@
513 return userPassword.Password, nil
514 }
515
516-func (self *UserRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) {
517+func (self *UserRepository) Create(ctx context.Context, createUser *repository.CreateUser) (uint, error) {
518 user := &User{
519 Username: createUser.Username,
520 Name: createUser.Name,
521@@ -154,7 +153,7 @@
522 return user.Model.ID, nil
523 }
524
525-func (self *UserRepository) Update(ctx context.Context, id uint, update *user.UpdateUser) error {
526+func (self *UserRepository) Update(ctx context.Context, id uint, update *repository.UpdateUser) error {
527 user := &User{
528 Model: gorm.Model{
529 ID: id,
530diff --git a/pkg/ext/middleware.go b/pkg/ext/middleware.go
531index bc23b9087ca3fab75190d884ec56b4d6472297f0..d255c6d70f398251ed0e7a7340bb9169fad7bf9a 100644
532--- a/pkg/ext/middleware.go
533+++ b/pkg/ext/middleware.go
534@@ -7,7 +7,7 @@
535 "github.com/sirupsen/logrus"
536 "github.com/valyala/fasthttp"
537
538- "git.sr.ht/~gabrielgio/img/pkg/components/user"
539+ "git.sr.ht/~gabrielgio/img/pkg/database/repository"
540 )
541
542 func HTML(next fasthttp.RequestHandler) fasthttp.RequestHandler {
543@@ -91,10 +91,10 @@ }
544 }
545
546 type InitialSetupMiddleware struct {
547- userRepository user.Repository
548+ userRepository repository.UserRepository
549 }
550
551-func NewInitialSetupMiddleware(userRepository user.Repository) *InitialSetupMiddleware {
552+func NewInitialSetupMiddleware(userRepository repository.UserRepository) *InitialSetupMiddleware {
553 return &InitialSetupMiddleware{
554 userRepository: userRepository,
555 }
556diff --git a/pkg/testkit/testkit.go b/pkg/testkit/testkit.go
557index 526e1b3b4ef1003bc6f35969befb9d3dc4fb24e7..3cc4afd4fa9f0ae6330b5aed8f1db23cdb7070c8 100644
558--- a/pkg/testkit/testkit.go
559+++ b/pkg/testkit/testkit.go
560@@ -9,18 +9,21 @@ "github.com/google/go-cmp/cmp"
561 )
562
563 func TestValue[T any](t *testing.T, method string, want, got T) {
564+ t.Helper()
565 if diff := cmp.Diff(want, got); diff != "" {
566 t.Errorf("%s() mismatch (-want +got):\n%s", method, diff)
567 }
568 }
569
570 func TestFatalError(t *testing.T, method string, err error) {
571+ t.Helper()
572 if err != nil {
573 t.Fatalf("%s() fatal error : %+v", method, err)
574 }
575 }
576
577 func TestError(t *testing.T, method string, want, got error) {
578+ t.Helper()
579 if !equalError(want, got) {
580 t.Errorf("%s() err mismatch want: %+v got %+v", method, want, got)
581 }
582diff --git a/pkg/view/media.go b/pkg/view/media.go
583index 22f950d8050cba87ad40c33a420cb80e29625dc0..66e302013f11217f069046868bc5c707b9a87cf9 100644
584--- a/pkg/view/media.go
585+++ b/pkg/view/media.go
586@@ -89,7 +89,7 @@ return err
587 }
588
589 ctx.Response.Header.SetContentType(media.MIMEType)
590- ctx.SendFile(media.Path)
591+ fasthttp.ServeFileUncompressed(ctx, media.Path)
592 return nil
593 }
594
595diff --git a/pkg/view/settings.go b/pkg/view/settings.go
596index e5acb1bbc57cfcb0325646114b7e95342e21c53a..954cc986086e6ba0d9429c32c800d9c91fbe6b90 100644
597--- a/pkg/view/settings.go
598+++ b/pkg/view/settings.go
599@@ -5,7 +5,7 @@ "github.com/valyala/fasthttp"
600
601 "git.sr.ht/~gabrielgio/img"
602 "git.sr.ht/~gabrielgio/img/pkg/components/settings"
603- "git.sr.ht/~gabrielgio/img/pkg/components/user"
604+ "git.sr.ht/~gabrielgio/img/pkg/database/repository"
605 "git.sr.ht/~gabrielgio/img/pkg/ext"
606 )
607
608@@ -13,18 +13,18 @@ type (
609 SettingsView struct {
610 // there is not need to create a controller for this
611 settingsRepository settings.Repository
612- userRepository user.Repository
613+ userRepository repository.UserRepository
614 }
615
616 SettingsPage struct {
617 Settings *settings.Settings
618- Users []*user.User
619+ Users []*repository.User
620 }
621 )
622
623 func NewSettingsView(
624 settingsRespository settings.Repository,
625- userRepository user.Repository,
626+ userRepository repository.UserRepository,
627 ) *SettingsView {
628 return &SettingsView{
629 settingsRepository: settingsRespository,