mirror of
https://github.com/eduardolat/pgbackweb.git
synced 2026-01-24 05:28:36 -06:00
Add logout all sessions functionality
This commit is contained in:
@@ -17,3 +17,16 @@ func (h *handlers) logoutHandler(c echo.Context) error {
|
||||
h.servs.AuthService.ClearSessionCookie(c)
|
||||
return htmx.RespondRedirect(c, "/auth/login")
|
||||
}
|
||||
|
||||
func (h *handlers) logoutAllSessionsHandler(c echo.Context) error {
|
||||
ctx := c.Request().Context()
|
||||
reqCtx := reqctx.GetCtx(c)
|
||||
|
||||
err := h.servs.AuthService.DeleteAllUserSessions(ctx, reqCtx.User.ID)
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
h.servs.AuthService.ClearSessionCookie(c)
|
||||
return htmx.RespondRedirect(c, "/auth/login")
|
||||
}
|
||||
|
||||
@@ -30,4 +30,5 @@ func MountRouter(
|
||||
}))
|
||||
|
||||
requireAuth.POST("/logout", h.logoutHandler)
|
||||
requireAuth.POST("/logout-all", h.logoutAllSessionsHandler)
|
||||
}
|
||||
|
||||
26
internal/view/web/dashboard/databases/index.go
Normal file
26
internal/view/web/dashboard/databases/index.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package databases
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/eduardolat/pgbackweb/internal/util/echoutil"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/layout"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/maragudk/gomponents"
|
||||
)
|
||||
|
||||
func (h *handlers) indexPageHandler(c echo.Context) error {
|
||||
return echoutil.RenderGomponent(c, http.StatusOK, indexPage())
|
||||
}
|
||||
|
||||
func indexPage() gomponents.Node {
|
||||
content := []gomponents.Node{
|
||||
component.H1Text("Databases"),
|
||||
}
|
||||
|
||||
return layout.Dashboard(layout.DashboardParams{
|
||||
Title: "Databases",
|
||||
Body: content,
|
||||
})
|
||||
}
|
||||
23
internal/view/web/dashboard/databases/router.go
Normal file
23
internal/view/web/dashboard/databases/router.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package databases
|
||||
|
||||
import (
|
||||
"github.com/eduardolat/pgbackweb/internal/service"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/middleware"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type handlers struct {
|
||||
servs *service.Service
|
||||
}
|
||||
|
||||
func newHandlers(servs *service.Service) *handlers {
|
||||
return &handlers{servs: servs}
|
||||
}
|
||||
|
||||
func MountRouter(
|
||||
parent *echo.Group, mids *middleware.Middleware, servs *service.Service,
|
||||
) {
|
||||
h := newHandlers(servs)
|
||||
|
||||
parent.GET("", h.indexPageHandler)
|
||||
}
|
||||
26
internal/view/web/dashboard/profile/close_all_sessions.go
Normal file
26
internal/view/web/dashboard/profile/close_all_sessions.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
lucide "github.com/eduardolat/gomponents-lucide"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/htmx"
|
||||
"github.com/maragudk/gomponents"
|
||||
"github.com/maragudk/gomponents/html"
|
||||
)
|
||||
|
||||
func closeAllSessionsForm() gomponents.Node {
|
||||
return component.CardBox(component.CardBoxParams{
|
||||
Children: []gomponents.Node{
|
||||
component.H2Text("Close all sessions"),
|
||||
component.PText("This will log you out from all devices including this one."),
|
||||
html.Button(
|
||||
htmx.HxPost("/auth/logout-all"),
|
||||
htmx.HxDisabledELT("this"),
|
||||
htmx.HxConfirm("Are you sure you want to close all your sessions?"),
|
||||
html.Class("mt-2 btn btn-error"),
|
||||
component.SpanText("Close all sessions"),
|
||||
lucide.LogOut(),
|
||||
),
|
||||
},
|
||||
})
|
||||
}
|
||||
36
internal/view/web/dashboard/profile/index.go
Normal file
36
internal/view/web/dashboard/profile/index.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/eduardolat/pgbackweb/internal/database/dbgen"
|
||||
"github.com/eduardolat/pgbackweb/internal/util/echoutil"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/reqctx"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/layout"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/maragudk/gomponents"
|
||||
"github.com/maragudk/gomponents/html"
|
||||
)
|
||||
|
||||
func (h *handlers) indexPageHandler(c echo.Context) error {
|
||||
reqCtx := reqctx.GetCtx(c)
|
||||
return echoutil.RenderGomponent(c, http.StatusOK, indexPage(reqCtx.User))
|
||||
}
|
||||
|
||||
func indexPage(user dbgen.User) gomponents.Node {
|
||||
content := []gomponents.Node{
|
||||
component.H1Text("Profile"),
|
||||
|
||||
html.Div(
|
||||
html.Class("mt-4 grid grid-cols-2 gap-4"),
|
||||
html.Div(updateUserForm(user)),
|
||||
html.Div(closeAllSessionsForm()),
|
||||
),
|
||||
}
|
||||
|
||||
return layout.Dashboard(layout.DashboardParams{
|
||||
Title: "Profile",
|
||||
Body: content,
|
||||
})
|
||||
}
|
||||
24
internal/view/web/dashboard/profile/router.go
Normal file
24
internal/view/web/dashboard/profile/router.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"github.com/eduardolat/pgbackweb/internal/service"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/middleware"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type handlers struct {
|
||||
servs *service.Service
|
||||
}
|
||||
|
||||
func newHandlers(servs *service.Service) *handlers {
|
||||
return &handlers{servs: servs}
|
||||
}
|
||||
|
||||
func MountRouter(
|
||||
parent *echo.Group, mids *middleware.Middleware, servs *service.Service,
|
||||
) {
|
||||
h := newHandlers(servs)
|
||||
|
||||
parent.GET("", h.indexPageHandler)
|
||||
parent.POST("", h.updateUserHandler)
|
||||
}
|
||||
111
internal/view/web/dashboard/profile/update_user.go
Normal file
111
internal/view/web/dashboard/profile/update_user.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
lucide "github.com/eduardolat/gomponents-lucide"
|
||||
"github.com/eduardolat/pgbackweb/internal/database/dbgen"
|
||||
"github.com/eduardolat/pgbackweb/internal/validate"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/reqctx"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/htmx"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/maragudk/gomponents"
|
||||
"github.com/maragudk/gomponents/html"
|
||||
)
|
||||
|
||||
func (h *handlers) updateUserHandler(c echo.Context) error {
|
||||
reqCtx := reqctx.GetCtx(c)
|
||||
ctx := c.Request().Context()
|
||||
|
||||
var formData struct {
|
||||
Name string `form:"name" validate:"required"`
|
||||
Email string `form:"email" validate:"required,email"`
|
||||
Password string `form:"password" validate:"omitempty,min=6,max=50"`
|
||||
PasswordConfirmation string `form:"password_confirmation" validate:"omitempty,eqfield=Password"`
|
||||
}
|
||||
if err := c.Bind(&formData); err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
if err := validate.Struct(&formData); err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
_, err := h.servs.UsersService.UpdateUser(ctx, dbgen.UsersServiceUpdateUserParams{
|
||||
ID: reqCtx.User.ID,
|
||||
Name: sql.NullString{String: formData.Name, Valid: true},
|
||||
Email: sql.NullString{String: formData.Email, Valid: true},
|
||||
Password: sql.NullString{String: formData.Password, Valid: formData.Password != ""},
|
||||
})
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
return htmx.RespondToastSuccess(c, "Profile updated")
|
||||
}
|
||||
|
||||
func updateUserForm(user dbgen.User) gomponents.Node {
|
||||
return component.CardBox(component.CardBoxParams{
|
||||
Children: []gomponents.Node{
|
||||
html.Form(
|
||||
htmx.HxPost("/dashboard/profile"),
|
||||
htmx.HxDisabledELT("find button"),
|
||||
html.Class("space-y-2"),
|
||||
|
||||
component.H2Text("Update profile"),
|
||||
|
||||
component.InputControl(component.InputControlParams{
|
||||
Name: "name",
|
||||
Label: "Full name",
|
||||
Placeholder: "Your full name",
|
||||
Required: true,
|
||||
Type: component.InputTypeText,
|
||||
AutoComplete: "name",
|
||||
Children: []gomponents.Node{
|
||||
html.Value(user.Name),
|
||||
},
|
||||
}),
|
||||
|
||||
component.InputControl(component.InputControlParams{
|
||||
Name: "email",
|
||||
Label: "Email",
|
||||
Placeholder: "Your email",
|
||||
Required: true,
|
||||
AutoComplete: "email",
|
||||
Type: component.InputTypeEmail,
|
||||
Children: []gomponents.Node{
|
||||
html.Value(user.Email),
|
||||
},
|
||||
}),
|
||||
|
||||
component.InputControl(component.InputControlParams{
|
||||
Name: "password",
|
||||
Label: "Change password",
|
||||
Placeholder: "New password",
|
||||
AutoComplete: "new-password",
|
||||
Type: component.InputTypePassword,
|
||||
HelpText: "Leave empty to keep your current password",
|
||||
}),
|
||||
|
||||
component.InputControl(component.InputControlParams{
|
||||
Name: "password_confirmation",
|
||||
Label: "Confirm password",
|
||||
Placeholder: "Confirm new password",
|
||||
AutoComplete: "new-password",
|
||||
Type: component.InputTypePassword,
|
||||
}),
|
||||
|
||||
html.Div(
|
||||
html.Class("flex justify-end items-center space-x-2 pt-2"),
|
||||
component.HxLoadingMd(),
|
||||
html.Button(
|
||||
html.Class("btn btn-primary"),
|
||||
html.Type("submit"),
|
||||
component.SpanText("Save changes"),
|
||||
lucide.Save(),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package dashboard
|
||||
import (
|
||||
"github.com/eduardolat/pgbackweb/internal/service"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/middleware"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/dashboard/databases"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/dashboard/profile"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/dashboard/summary"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
@@ -11,4 +13,6 @@ func MountRouter(
|
||||
parent *echo.Group, mids *middleware.Middleware, servs *service.Service,
|
||||
) {
|
||||
summary.MountRouter(parent.Group(""), mids, servs)
|
||||
databases.MountRouter(parent.Group("/databases"), mids, servs)
|
||||
profile.MountRouter(parent.Group("/profile"), mids, servs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user