lens @ 249ee195ce52ee4a4defeb67a33ef353919d3a11

feat: Add user list UI

Fill user settings UI with actual data.
diff --git a/README.md b/README.md
index 6103dbfc3432ba7615a19ab7d4026389bd854e9b..9ff9bfd53f0a3058505d4b70861d40120fb3537d 100644
--- a/README.md
+++ b/README.md
@@ -13,3 +13,5 @@ * Alpine package and demo site
 * Single image viewer and show exif info (not sure how yet)
 * User base root folder 
 * Albuns
+* Testing. Since I still on initial iteration phases I'm not adding as many
+  testing as I'd like to. Once I set on most of the design I'll add testing.
diff --git a/cmd/server/main.go b/cmd/server/main.go
index 4ca39de019df146d6b4348036a23abaa1087d090..d7c2fd64ce0eaf97d3afc4e3d3d6337ac5995109 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -103,7 +103,7 @@ 	// view
 	for _, v := range []view.View{
 		view.NewAuthView(userController),
 		view.NewFileSystemView(*fileSystemController, settingsRepository),
-		view.NewSettingsView(settingsRepository),
+		view.NewSettingsView(settingsRepository, userRepository),
 		view.NewMediaView(mediaRepository),
 	} {
 		v.SetMyselfIn(extRouter)
diff --git a/pkg/components/auth/controller.go b/pkg/components/auth/controller.go
index 4da607129965146d0a5cef01599d464e421f5875..a81a1c0f802acc5a4c90bcc400d2d9f913c73b9b 100644
--- a/pkg/components/auth/controller.go
+++ b/pkg/components/auth/controller.go
@@ -41,17 +41,3 @@ 		Username: string(username),
 	}
 	return ext.WriteToken(token, c.key)
 }
-
-func (c *Controller) Register(ctx context.Context, username, password []byte) error {
-	hash, err := bcrypt.GenerateFromPassword(password, bcrypt.MinCost)
-	if err != nil {
-		return err
-	}
-
-	_, err = c.repository.Create(ctx, &CreateUser{
-		Username: string(username),
-		Password: hash,
-	})
-
-	return err
-}
diff --git a/pkg/components/auth/model.go b/pkg/components/auth/model.go
index e46ef4979fc10a82e1822ab6a692c19774093525..dd6ce5036b91127e13e37c4e57b7baa13b486a1a 100644
--- a/pkg/components/auth/model.go
+++ b/pkg/components/auth/model.go
@@ -3,30 +3,8 @@
 import "context"
 
 type (
-	// TODO: move to user later
-	User struct {
-		ID       uint
-		Username string
-		Name     string
-	}
-
-	// TODO: move to user later
-	UpdateUser struct {
-		Username string
-		Name     string
-	}
-
-	// TODO: move to user later
-	CreateUser struct {
-		Username string
-		Name     string
-		Password []byte
-	}
-
 	Repository interface {
 		GetIDByUsername(ctx context.Context, username string) (uint, error)
 		GetPassword(ctx context.Context, id uint) ([]byte, error)
-		// TODO: move to user later
-		Create(ctx context.Context, createUser *CreateUser) (uint, error)
 	}
 )
diff --git a/pkg/components/user/controller.go b/pkg/components/user/controller.go
new file mode 100644
index 0000000000000000000000000000000000000000..a00006b65468ecad731002a1e2c54884759656ed
--- /dev/null
+++ b/pkg/components/user/controller.go
@@ -0,0 +1 @@
+package user
diff --git a/pkg/components/user/model.go b/pkg/components/user/model.go
new file mode 100644
index 0000000000000000000000000000000000000000..f957c39a95fb49179c319674a6c31827bebb695c
--- /dev/null
+++ b/pkg/components/user/model.go
@@ -0,0 +1,33 @@
+package user
+
+import "context"
+
+type (
+	User struct {
+		ID       uint
+		Username string
+		Name     string
+		IsAdmin  bool
+		Path     string
+	}
+
+	UpdateUser struct {
+		Username string
+		Name     string
+		Password *string
+	}
+
+	CreateUser struct {
+		Username string
+		Name     string
+		Password string
+		IsAdmin  bool
+		Path     string
+	}
+
+	Repository interface {
+		List(ctx context.Context) ([]*User, error)
+		Create(ctx context.Context, createUser *CreateUser) 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 d449b05078914829508c79dd8da8583b7f66cbc9..2d74162713c10e1ed292a1dc116404e862f77bd3 100644
--- a/pkg/database/sql/user.go
+++ b/pkg/database/sql/user.go
@@ -7,7 +7,7 @@ 	"golang.org/x/crypto/bcrypt"
 	"gorm.io/gorm"
 
 	"git.sr.ht/~gabrielgio/img/pkg/components/auth"
-	user "git.sr.ht/~gabrielgio/img/pkg/components/auth"
+	"git.sr.ht/~gabrielgio/img/pkg/components/user"
 )
 
 type (
@@ -16,6 +16,8 @@ 		gorm.Model
 		Username string
 		Name     string
 		Password string
+		IsAdmin  bool
+		Path     string
 	}
 
 	Users []*User
@@ -26,6 +28,7 @@ 	}
 )
 
 var _ auth.Repository = &UserRepository{}
+var _ user.Repository = &UserRepository{}
 
 func NewUserRepository(db *gorm.DB) *UserRepository {
 	return &UserRepository{
@@ -38,6 +41,8 @@ 	return &user.User{
 		ID:       self.Model.ID,
 		Name:     self.Name,
 		Username: self.Username,
+		Path:     self.Path,
+		IsAdmin:  self.IsAdmin,
 	}
 }
 
@@ -63,6 +68,8 @@ 	if !exists {
 		hash, _ := bcrypt.GenerateFromPassword([]byte("admin"), bcrypt.MinCost)
 		self.db.Save(&User{
 			Username: "admin",
+			Path:     "/",
+			IsAdmin:  true,
 			Password: string(hash),
 		})
 	}
@@ -130,7 +137,7 @@
 	return userPassword.Password, nil
 }
 
-func (self *UserRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) {
+func (self *UserRepository) Create(ctx context.Context, createUser *user.CreateUser) error {
 	user := &User{
 		Username: createUser.Username,
 		Name:     createUser.Name,
@@ -141,10 +148,10 @@ 	result := self.db.
 		WithContext(ctx).
 		Create(user)
 	if result.Error != nil {
-		return 0, result.Error
+		return result.Error
 	}
 
-	return user.Model.ID, nil
+	return nil
 }
 
 func (self *UserRepository) Update(ctx context.Context, id uint, update *user.UpdateUser) error {
diff --git a/pkg/view/auth.go b/pkg/view/auth.go
index 5c83eba0225998cda97795f1747f3d73894e9f4d..d44424d64290d5877761bcc1229b9244551ca08b 100644
--- a/pkg/view/auth.go
+++ b/pkg/view/auth.go
@@ -64,23 +64,6 @@ 	}
 	return nil
 }
 
-func (v *AuthView) RegisterView(ctx *fasthttp.RequestCtx) error {
-	return img.Render[interface{}](ctx, "register.html", nil)
-}
-
-func (v *AuthView) Register(ctx *fasthttp.RequestCtx) error {
-	username := ctx.FormValue("username")
-	password := ctx.FormValue("password")
-
-	err := v.userController.Register(ctx, username, password)
-	if err != nil {
-		return err
-	}
-
-	ctx.Redirect("/login", 307)
-	return nil
-}
-
 func Index(ctx *fasthttp.RequestCtx) {
 	ctx.Redirect("/login", 307)
 }
@@ -88,9 +71,6 @@
 func (v *AuthView) SetMyselfIn(r *ext.Router) {
 	r.GET("/login", v.LoginView)
 	r.POST("/login", v.Login)
-
-	r.GET("/register", v.RegisterView)
-	r.POST("/register", v.Register)
 
 	r.GET("/logout", v.Logout)
 	r.POST("/logout", v.Logout)
diff --git a/pkg/view/settings.go b/pkg/view/settings.go
index 746dee4df99001f92e4b6703fee352ca4cb76998..e5acb1bbc57cfcb0325646114b7e95342e21c53a 100644
--- a/pkg/view/settings.go
+++ b/pkg/view/settings.go
@@ -5,28 +5,50 @@ 	"github.com/valyala/fasthttp"
 
 	"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/ext"
 )
 
-type SettingsView struct {
-	// there is not need to create a controller for this
-	repository settings.Repository
-}
+type (
+	SettingsView struct {
+		// there is not need to create a controller for this
+		settingsRepository settings.Repository
+		userRepository     user.Repository
+	}
+
+	SettingsPage struct {
+		Settings *settings.Settings
+		Users    []*user.User
+	}
+)
 
-func NewSettingsView(respository settings.Repository) *SettingsView {
+func NewSettingsView(
+	settingsRespository settings.Repository,
+	userRepository user.Repository,
+) *SettingsView {
 	return &SettingsView{
-		repository: respository,
+		settingsRepository: settingsRespository,
+		userRepository:     userRepository,
 	}
 }
 
 func (self *SettingsView) Index(ctx *fasthttp.RequestCtx) error {
-	s, err := self.repository.Load(ctx)
+	s, err := self.settingsRepository.Load(ctx)
+	if err != nil {
+		return err
+	}
+
+	users, err := self.userRepository.List(ctx)
 	if err != nil {
 		return err
 	}
-	return img.Render(ctx, "settings.html", &img.HTMLView[*settings.Settings]{
+
+	return img.Render(ctx, "settings.html", &img.HTMLView[*SettingsPage]{
 		Title: "Settings",
-		Data:  s,
+		Data: &SettingsPage{
+			Settings: s,
+			Users:    users,
+		},
 	})
 }
 
@@ -36,7 +58,7 @@ 		showMode  = string(ctx.FormValue("showMode")) == "on"
 		showOwner = string(ctx.FormValue("showOwner")) == "on"
 	)
 
-	err := self.repository.Save(ctx, &settings.Settings{
+	err := self.settingsRepository.Save(ctx, &settings.Settings{
 		ShowMode:  showMode,
 		ShowOwner: showOwner,
 	})
diff --git a/scss/main.scss b/scss/main.scss
index 033315f51b4c6b75ed6da68eb9d5faa25656409b..7028622f93c495f755a63365a8093ba4cc8c1264 100644
--- a/scss/main.scss
+++ b/scss/main.scss
@@ -34,15 +34,20 @@
 .input, .button{
     border-radius: 0;
 }
-
-.file-row {
+.wide-column {
     width: 100%;
+}
+.is-mono {
     font-family: monospace;
 }
 
 nav {
     border-bottom: 1px solid;
     margin: auto;
+}
+
+a.is-danger {
+    color: $danger
 }
 
 .container {
diff --git a/templates/fs.html b/templates/fs.html
index 608289d971d4f83e1c9b5155f63f6059084b5b85..a44d78f441b53a2e1229120696a4c081908679dd 100644
--- a/templates/fs.html
+++ b/templates/fs.html
@@ -11,7 +11,7 @@       </div>
   </div>
   {{range .Data.Page.Files}}
   <div class="panel-block">
-      <div class="columns file-row is-gapless is-mobile">
+      <div class="columns wide-column is-mono is-gapless is-mobile">
           <div class="column">
               {{if $.Data.ShowMode}}{{.Info.Mode}}&emsp;{{end}}
               {{if $.Data.ShowOwner}}{{.Info.Sys.Gid}}:{{.Info.Sys.Uid}}&emsp;{{end}}
diff --git a/templates/settings.html b/templates/settings.html
index 2aa1a80ea944113afeac78ecc08cac704956187d..8c08773338919637ec0c3cb18e2b050f22945a66 100644
--- a/templates/settings.html
+++ b/templates/settings.html
@@ -7,7 +7,7 @@         <form action="/settings/", method="post">
             <div class="field">
                 <div class="control">
                     <label class="checkbox">
-                        <input type="checkbox" id="showMode" name="showMode" {{if .Data.ShowMode}}checked{{end}}>
+                        <input type="checkbox" id="showMode" name="showMode" {{if .Data.Settings.ShowMode}}checked{{end}}>
                         Show File Modes
                     </label>
                 </div>
@@ -15,7 +15,7 @@             </div>
             <div class="field">
                 <div class="control">
                     <label class="checkbox">
-                        <input type="checkbox" id="showOwner" name="showOwner" {{if .Data.ShowOwner}}checked{{end}}>
+                        <input type="checkbox" id="showOwner" name="showOwner" {{if .Data.Settings.ShowOwner}}checked{{end}}>
                         Show File Owner
                     </label>
                 </div>
@@ -26,38 +26,19 @@             </div>
         </form>
     </div>
     <div class="column">
-        <div class="table-container">
-            <table class="table">
-                <thead>
-                    <tr>
-                        <th>Username</th>
-                        <th>Path</th>
-                        <th>Is Admin?</th>
-                        <th>Action</th>
-                    </tr>
-                </thead>
-                <tbody>
-                    <tr>
-                        <td>gabrielgio</td>
-                        <td>/home/gabrielgio</td>
-                        <td>yes</td>
-                        <td>
-                            <a href="#" class="button is-small">Edit</button>
-                            <a href="#" class="button is-small is-danger">Delete</button>
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>beatriz</td>
-                        <td>/home/beatriz</td>
-                        <td>no</td>
-                        <td>
-                            <a href="#" class="button is-small">Edit</button>
-                            <a href="#" class="button is-small is-danger">Delete</button>
-                        </td>
-                    </tr>
-                </tbody>
-            </table>
+        {{range .Data.Users}}
+        <div class="panel-block">
+            <div class="columns wide-column is-gapless is-mobile">
+                <div class="column">
+                    {{.Username}}
+                </div>
+                <div class="column">
+                    {{.Path}}
+                </div>
+                <div class="column  has-text-right"><a href="#">Edit</a> / <a href="#" class="is-danger">Delete</a></div>
+            </div>
         </div>
+        {{end}}
     </div>
 </div>
 {{end}}