fix: extract html rendering
All checks were successful
Build Docker Image / Build-Docker-Image (push) Successful in 43s
All checks were successful
Build Docker Image / Build-Docker-Image (push) Successful in 43s
This commit is contained in:
136
handler/auth.go
136
handler/auth.go
@@ -2,7 +2,6 @@ package handler
|
||||
|
||||
import (
|
||||
"me-fit/service"
|
||||
"me-fit/template"
|
||||
"me-fit/template/auth"
|
||||
"me-fit/types"
|
||||
"me-fit/utils"
|
||||
@@ -18,32 +17,37 @@ type HandlerAuth interface {
|
||||
}
|
||||
|
||||
type HandlerAuthImpl struct {
|
||||
service service.AuthService
|
||||
serverSettings *types.ServerSettings
|
||||
service service.AuthService
|
||||
render *Render
|
||||
}
|
||||
|
||||
func NewHandlerAuth(service service.AuthService, serverSettings *types.ServerSettings) HandlerAuth {
|
||||
func NewHandlerAuth(service service.AuthService, render *Render) HandlerAuth {
|
||||
return HandlerAuthImpl{
|
||||
service: service,
|
||||
serverSettings: serverSettings,
|
||||
service: service,
|
||||
render: render,
|
||||
}
|
||||
}
|
||||
|
||||
func (handler HandlerAuthImpl) Handle(router *http.ServeMux) {
|
||||
// Don't use auth middleware for these routes, as it makes redirecting very difficult, if the mail is not yet verified
|
||||
router.Handle("/auth/signin", handler.handleSignInPage())
|
||||
router.Handle("/auth/signup", handler.handleSignUpPage())
|
||||
router.Handle("/auth/verify", handler.handleSignUpVerifyPage()) // Hint for the user to verify their email
|
||||
router.Handle("/auth/delete-account", handler.handleDeleteAccountPage())
|
||||
router.Handle("/auth/verify-email", handler.HandleSignUpVerifyResponsePage()) // The link contained in the email
|
||||
router.Handle("/auth/change-password", handler.handleChangePasswordPage())
|
||||
router.Handle("/auth/reset-password", handler.handleResetPasswordPage())
|
||||
router.Handle("/api/auth/signup", handler.handleSignUp())
|
||||
router.Handle("/api/auth/signin", handler.handleSignIn())
|
||||
router.Handle("/api/auth/signout", handler.handleSignOut())
|
||||
router.Handle("/api/auth/delete-account", handler.HandleDeleteAccountComp())
|
||||
router.Handle("/auth/verify", handler.handleSignUpVerifyPage())
|
||||
router.Handle("/api/auth/verify-resend", handler.HandleVerifyResendComp())
|
||||
router.Handle("/auth/verify-email", handler.HandleSignUpVerifyResponsePage())
|
||||
router.Handle("/api/auth/signup", handler.handleSignUp())
|
||||
|
||||
router.Handle("/auth/signin", handler.handleSignInPage())
|
||||
router.Handle("/api/auth/signin", handler.handleSignIn())
|
||||
|
||||
router.Handle("/api/auth/signout", handler.handleSignOut())
|
||||
|
||||
router.Handle("/auth/delete-account", handler.handleDeleteAccountPage())
|
||||
router.Handle("/api/auth/delete-account", handler.HandleDeleteAccountComp())
|
||||
|
||||
router.Handle("/auth/change-password", handler.handleChangePasswordPage())
|
||||
router.Handle("/api/auth/change-password", handler.HandleChangePasswordComp())
|
||||
|
||||
router.Handle("/auth/reset-password", handler.handleResetPasswordPage())
|
||||
router.Handle("/api/auth/reset-password", handler.HandleForgotPasswordComp())
|
||||
router.Handle("/api/auth/reset-password-actual", handler.HandleForgotPasswordResponseComp())
|
||||
}
|
||||
@@ -54,24 +58,19 @@ var (
|
||||
|
||||
func (handler HandlerAuthImpl) handleSignInPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := handler.service.GetUserFromSessionId(utils.GetSessionID(r))
|
||||
if err != nil {
|
||||
userComp := service.UserInfoComp(nil)
|
||||
signIn := auth.SignInOrUpComp(true)
|
||||
err := template.Layout(signIn, userComp, handler.serverSettings.Environment).Render(r.Context(), w)
|
||||
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render sign in page", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
user, _ := handler.service.GetUserFromSessionId(utils.GetSessionID(r))
|
||||
if user != nil {
|
||||
if !user.EmailVerified {
|
||||
utils.DoRedirect(w, r, "/auth/verify")
|
||||
} else {
|
||||
utils.DoRedirect(w, r, "/")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !user.EmailVerified {
|
||||
utils.DoRedirect(w, r, "/auth/verify")
|
||||
} else {
|
||||
utils.DoRedirect(w, r, "/")
|
||||
}
|
||||
comp := auth.SignInOrUpComp(true)
|
||||
|
||||
handler.render.RenderLayout(r, w, comp, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,23 +121,19 @@ func (handler HandlerAuthImpl) handleSignIn() http.HandlerFunc {
|
||||
|
||||
func (handler HandlerAuthImpl) handleSignUpPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := handler.service.GetUserFromSessionId(utils.GetSessionID(r))
|
||||
if err != nil {
|
||||
userComp := service.UserInfoComp(nil)
|
||||
signUpComp := auth.SignInOrUpComp(false)
|
||||
err := template.Layout(signUpComp, userComp, handler.serverSettings.Environment).Render(r.Context(), w)
|
||||
user, _ := handler.service.GetUserFromSessionId(utils.GetSessionID(r))
|
||||
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render sign up page", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
if user != nil {
|
||||
if !user.EmailVerified {
|
||||
utils.DoRedirect(w, r, "/auth/verify")
|
||||
} else {
|
||||
utils.DoRedirect(w, r, "/")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !user.EmailVerified {
|
||||
utils.DoRedirect(w, r, "/auth/verify")
|
||||
} else {
|
||||
utils.DoRedirect(w, r, "/")
|
||||
}
|
||||
signUpComp := auth.SignInOrUpComp(false)
|
||||
handler.render.RenderLayout(r, w, signUpComp, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,22 +193,19 @@ func (handler HandlerAuthImpl) handleSignOut() http.HandlerFunc {
|
||||
|
||||
func (handler HandlerAuthImpl) handleSignUpVerifyPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := handler.service.GetUserFromSessionId(utils.GetSessionID(r))
|
||||
if err != nil {
|
||||
user, _ := handler.service.GetUserFromSessionId(utils.GetSessionID(r))
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
}
|
||||
|
||||
if user.EmailVerified {
|
||||
utils.DoRedirect(w, r, "/")
|
||||
} else {
|
||||
userComp := service.UserInfoComp(user)
|
||||
signIn := auth.VerifyComp()
|
||||
err := template.Layout(signIn, userComp, handler.serverSettings.Environment).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render verify page", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
signIn := auth.VerifyComp()
|
||||
handler.render.RenderLayout(r, w, signIn, user)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,13 +217,8 @@ func (handler HandlerAuthImpl) handleDeleteAccountPage() http.HandlerFunc {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
}
|
||||
|
||||
userComp := service.UserInfoComp(user)
|
||||
comp := auth.DeleteAccountComp()
|
||||
err = template.Layout(comp, userComp, handler.serverSettings.Environment).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render delete account page", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
handler.render.RenderLayout(r, w, comp, user)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,15 +231,11 @@ func (handler HandlerAuthImpl) handleChangePasswordPage() http.HandlerFunc {
|
||||
|
||||
if user == nil && !isPasswordReset {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
} else {
|
||||
userComp := service.UserInfoComp(user)
|
||||
comp := auth.ChangePasswordComp(isPasswordReset)
|
||||
err := template.Layout(comp, userComp, handler.serverSettings.Environment).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render change password page", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
comp := auth.ChangePasswordComp(isPasswordReset)
|
||||
handler.render.RenderLayout(r, w, comp, user)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,15 +245,11 @@ func (handler HandlerAuthImpl) handleResetPasswordPage() http.HandlerFunc {
|
||||
user, err := handler.service.GetUserFromSessionId(utils.GetSessionID(r))
|
||||
if err != nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
}
|
||||
|
||||
userComp := service.UserInfoComp(user)
|
||||
comp := auth.ResetPasswordComp()
|
||||
err = template.Layout(comp, userComp, handler.serverSettings.Environment).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render change password page", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
handler.render.RenderLayout(r, w, comp, user)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,13 +262,8 @@ func (handler HandlerAuthImpl) HandleResetPasswordPage() http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
userComp := service.UserInfoComp(user)
|
||||
comp := auth.ResetPasswordComp()
|
||||
err = template.Layout(comp, userComp, handler.serverSettings.Environment).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render change password page", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
handler.render.RenderLayout(r, w, comp, user)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,7 +356,7 @@ func (handler HandlerAuthImpl) HandleForgotPasswordComp() http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
err := handler.service.ForgotPassword(email)
|
||||
err := handler.service.SendForgotPasswordMail(email)
|
||||
if err != nil {
|
||||
utils.TriggerToast(w, r, "error", "Internal Server Error")
|
||||
} else {
|
||||
@@ -409,7 +383,7 @@ func (handler HandlerAuthImpl) HandleForgotPasswordResponseComp() http.HandlerFu
|
||||
|
||||
newPass := r.FormValue("new-password")
|
||||
|
||||
err = handler.service.ForgotPasswordResponse(token, newPass)
|
||||
err = handler.service.ForgotPassword(token, newPass)
|
||||
if err != nil {
|
||||
utils.TriggerToast(w, r, "error", err.Error())
|
||||
} else {
|
||||
|
||||
@@ -3,7 +3,6 @@ package handler
|
||||
import (
|
||||
"me-fit/service"
|
||||
"me-fit/template"
|
||||
"me-fit/types"
|
||||
"me-fit/utils"
|
||||
|
||||
"net/http"
|
||||
@@ -16,14 +15,14 @@ type IndexHandler interface {
|
||||
}
|
||||
|
||||
type IndexHandlerImpl struct {
|
||||
service service.AuthService
|
||||
serverSettings *types.ServerSettings
|
||||
service service.AuthService
|
||||
render *Render
|
||||
}
|
||||
|
||||
func NewIndexHandler(service service.AuthService, serverSettings *types.ServerSettings) IndexHandler {
|
||||
func NewIndexHandler(service service.AuthService, render *Render) IndexHandler {
|
||||
return IndexHandlerImpl{
|
||||
service: service,
|
||||
serverSettings: serverSettings,
|
||||
service: service,
|
||||
render: render,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,20 +34,15 @@ func (handler IndexHandlerImpl) handleIndexAnd404() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := handler.service.GetUserFromSessionId(utils.GetSessionID(r))
|
||||
|
||||
var comp templ.Component = nil
|
||||
userComp := service.UserInfoComp(user)
|
||||
var comp templ.Component
|
||||
|
||||
if r.URL.Path != "/" {
|
||||
comp = template.Layout(template.NotFound(), userComp, handler.serverSettings.Environment)
|
||||
comp = template.NotFound()
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
} else {
|
||||
comp = template.Layout(template.Index(), userComp, handler.serverSettings.Environment)
|
||||
comp = template.Index()
|
||||
}
|
||||
|
||||
err := comp.Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render index", err)
|
||||
http.Error(w, "Failed to render index", http.StatusInternalServerError)
|
||||
}
|
||||
handler.render.RenderLayout(r, w, comp, user)
|
||||
}
|
||||
}
|
||||
|
||||
47
handler/render.go
Normal file
47
handler/render.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"me-fit/service"
|
||||
"me-fit/template"
|
||||
"me-fit/template/auth"
|
||||
"me-fit/types"
|
||||
"me-fit/utils"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
)
|
||||
|
||||
type Render struct {
|
||||
serverSettings *types.ServerSettings
|
||||
}
|
||||
|
||||
func NewRender(serverSettings *types.ServerSettings) *Render {
|
||||
return &Render{
|
||||
serverSettings: serverSettings,
|
||||
}
|
||||
}
|
||||
|
||||
func (render *Render) Render(r *http.Request, w http.ResponseWriter, comp templ.Component) {
|
||||
err := comp.Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render layout", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (render *Render) RenderLayout(r *http.Request, w http.ResponseWriter, slot templ.Component, user *service.User) {
|
||||
userComp := render.getUserComp(user)
|
||||
layout := template.Layout(slot, userComp, render.serverSettings.Environment)
|
||||
|
||||
render.Render(r, w, layout)
|
||||
}
|
||||
|
||||
func (render *Render) getUserComp(user *service.User) templ.Component {
|
||||
|
||||
if user != nil {
|
||||
return auth.UserComp(user.Email)
|
||||
} else {
|
||||
return auth.UserComp("")
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"me-fit/service"
|
||||
"me-fit/template"
|
||||
"me-fit/template/workout"
|
||||
"me-fit/types"
|
||||
"me-fit/utils"
|
||||
|
||||
"log/slog"
|
||||
@@ -18,16 +16,16 @@ type WorkoutHandler interface {
|
||||
}
|
||||
|
||||
type WorkoutHandlerImpl struct {
|
||||
service service.WorkoutService
|
||||
auth service.AuthService
|
||||
serverSettings *types.ServerSettings
|
||||
service service.WorkoutService
|
||||
auth service.AuthService
|
||||
render *Render
|
||||
}
|
||||
|
||||
func NewWorkoutHandler(service service.WorkoutService, auth service.AuthService, serverSettings *types.ServerSettings) WorkoutHandler {
|
||||
func NewWorkoutHandler(service service.WorkoutService, auth service.AuthService, render *Render) WorkoutHandler {
|
||||
return WorkoutHandlerImpl{
|
||||
service: service,
|
||||
auth: auth,
|
||||
serverSettings: serverSettings,
|
||||
service: service,
|
||||
auth: auth,
|
||||
render: render,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,13 +45,8 @@ func (handler WorkoutHandlerImpl) handleWorkoutPage() http.HandlerFunc {
|
||||
}
|
||||
|
||||
currentDate := time.Now().Format("2006-01-02")
|
||||
inner := workout.WorkoutComp(currentDate)
|
||||
userComp := service.UserInfoComp(user)
|
||||
err = template.Layout(inner, userComp, handler.serverSettings.Environment).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Failed to render workout page", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
comp := workout.WorkoutComp(currentDate)
|
||||
handler.render.RenderLayout(r, w, comp, user)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,12 +72,8 @@ func (handler WorkoutHandlerImpl) handleAddWorkout() http.HandlerFunc {
|
||||
}
|
||||
wor := workout.Workout{Id: wo.RowId, Date: wo.Date, Type: wo.Type, Sets: wo.Sets, Reps: wo.Reps}
|
||||
|
||||
err = workout.WorkoutItemComp(wor, true).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Could not render workoutitem", err)
|
||||
utils.TriggerToast(w, r, "error", "Internal Server Error")
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
comp := workout.WorkoutItemComp(wor, true)
|
||||
handler.render.Render(r, w, comp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,12 +95,8 @@ func (handler WorkoutHandlerImpl) handleGetWorkout() http.HandlerFunc {
|
||||
wos = append(wos, workout.Workout{Id: wo.RowId, Date: wo.Date, Type: wo.Type, Sets: wo.Sets, Reps: wo.Reps})
|
||||
}
|
||||
|
||||
err = workout.WorkoutListComp(wos).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
utils.LogError("Could not render workoutlist", err)
|
||||
utils.TriggerToast(w, r, "error", "Internal Server Error")
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
comp := workout.WorkoutListComp(wos)
|
||||
handler.render.Render(r, w, comp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
8
main.go
8
main.go
@@ -112,12 +112,14 @@ func createHandler(d *sql.DB, serverSettings *types.ServerSettings) http.Handler
|
||||
randomService := service.NewRandomServiceImpl()
|
||||
clockService := service.NewClockServiceImpl()
|
||||
mailService := service.NewMailServiceImpl(serverSettings)
|
||||
|
||||
authService := service.NewAuthServiceImpl(authDb, randomService, clockService, mailService, serverSettings)
|
||||
workoutService := service.NewWorkoutServiceImpl(workoutDb, randomService, clockService, mailService, serverSettings)
|
||||
|
||||
indexHandler := handler.NewIndexHandler(authService, serverSettings)
|
||||
authHandler := handler.NewHandlerAuth(authService, serverSettings)
|
||||
workoutHandler := handler.NewWorkoutHandler(workoutService, authService, serverSettings)
|
||||
render := handler.NewRender(serverSettings)
|
||||
indexHandler := handler.NewIndexHandler(authService, render)
|
||||
authHandler := handler.NewHandlerAuth(authService, render)
|
||||
workoutHandler := handler.NewWorkoutHandler(workoutService, authService, render)
|
||||
|
||||
indexHandler.Handle(router)
|
||||
|
||||
|
||||
@@ -9,12 +9,10 @@ import (
|
||||
"time"
|
||||
|
||||
"me-fit/db"
|
||||
"me-fit/template/auth"
|
||||
mailTemplate "me-fit/template/mail"
|
||||
"me-fit/types"
|
||||
"me-fit/utils"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
@@ -56,15 +54,19 @@ func NewSession(session *db.Session, user *User) *Session {
|
||||
}
|
||||
|
||||
type AuthService interface {
|
||||
SignIn(email string, password string) (*Session, error)
|
||||
SignUp(email string, password string) (*User, error)
|
||||
SendVerificationMail(userId uuid.UUID, email string)
|
||||
VerifyUserEmail(token string) error
|
||||
|
||||
SignIn(email string, password string) (*Session, error)
|
||||
SignOut(sessionId string) error
|
||||
|
||||
DeleteAccount(user *User) error
|
||||
|
||||
ChangePassword(user *User, currPass, newPass string) error
|
||||
ForgotPassword(email string) error
|
||||
ForgotPasswordResponse(token string, newPass string) error
|
||||
|
||||
SendForgotPasswordMail(email string) error
|
||||
ForgotPassword(token string, newPass string) error
|
||||
|
||||
GetUserFromSessionId(sessionId string) (*User, error)
|
||||
}
|
||||
@@ -273,15 +275,6 @@ func (service AuthServiceImpl) GetUserFromSessionId(sessionId string) (*User, er
|
||||
|
||||
// TODO
|
||||
|
||||
func UserInfoComp(user *User) templ.Component {
|
||||
|
||||
if user != nil {
|
||||
return auth.UserComp(user.Email)
|
||||
} else {
|
||||
return auth.UserComp("")
|
||||
}
|
||||
}
|
||||
|
||||
func (service AuthServiceImpl) DeleteAccount(user *User) error {
|
||||
|
||||
err := service.dbAuth.DeleteUser(user.Id)
|
||||
@@ -326,7 +319,7 @@ func (service AuthServiceImpl) ChangePassword(user *User, currPass, newPass stri
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service AuthServiceImpl) ForgotPassword(email string) error {
|
||||
func (service AuthServiceImpl) SendForgotPasswordMail(email string) error {
|
||||
|
||||
tokenStr, err := service.randomGenerator.String(32)
|
||||
if err != nil {
|
||||
@@ -360,7 +353,7 @@ func (service AuthServiceImpl) ForgotPassword(email string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service AuthServiceImpl) ForgotPasswordResponse(tokenStr string, newPass string) error {
|
||||
func (service AuthServiceImpl) ForgotPassword(tokenStr string, newPass string) error {
|
||||
|
||||
if !isPasswordValid(newPass) {
|
||||
return ErrInvalidPassword
|
||||
|
||||
Reference in New Issue
Block a user