diff --git a/db/auth.go b/db/auth.go index 0a73aa2..82aabf0 100644 --- a/db/auth.go +++ b/db/auth.go @@ -2,8 +2,8 @@ package db import ( "log/slog" + "me-fit/log" "me-fit/types" - "me-fit/utils" "database/sql" "errors" @@ -116,7 +116,7 @@ func (db AuthDbSqlite) InsertUser(user *User) error { return ErrUserExists } - utils.LogError("SQL error InsertUser", err) + log.Error("SQL error InsertUser", err) return types.ErrInternal } @@ -131,7 +131,7 @@ func (db AuthDbSqlite) UpdateUser(user *User) error { user.EmailVerified, user.EmailVerifiedAt, user.Password, user.Id) if err != nil { - utils.LogError("SQL error UpdateUser", err) + log.Error("SQL error UpdateUser", err) return types.ErrInternal } @@ -157,7 +157,7 @@ func (db AuthDbSqlite) GetUserByEmail(email string) (*User, error) { if err == sql.ErrNoRows { return nil, ErrNotFound } else { - utils.LogError("SQL error GetUser", err) + log.Error("SQL error GetUser", err) return nil, types.ErrInternal } } @@ -184,7 +184,7 @@ func (db AuthDbSqlite) GetUser(userId uuid.UUID) (*User, error) { if err == sql.ErrNoRows { return nil, ErrNotFound } else { - utils.LogError("SQL error GetUser", err) + log.Error("SQL error GetUser", err) return nil, types.ErrInternal } } @@ -196,41 +196,41 @@ func (db AuthDbSqlite) DeleteUser(userId uuid.UUID) error { tx, err := db.db.Begin() if err != nil { - utils.LogError("Could not start transaction", err) + log.Error("Could not start transaction", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM workout WHERE user_id = ?", userId) if err != nil { _ = tx.Rollback() - utils.LogError("Could not delete workouts", err) + log.Error("Could not delete workouts", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM user_token WHERE user_uuid = ?", userId) if err != nil { _ = tx.Rollback() - utils.LogError("Could not delete user tokens", err) + log.Error("Could not delete user tokens", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM session WHERE user_uuid = ?", userId) if err != nil { _ = tx.Rollback() - utils.LogError("Could not delete sessions", err) + log.Error("Could not delete sessions", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM user WHERE user_uuid = ?", userId) if err != nil { _ = tx.Rollback() - utils.LogError("Could not delete user", err) + log.Error("Could not delete user", err) return types.ErrInternal } err = tx.Commit() if err != nil { - utils.LogError("Could not commit transaction", err) + log.Error("Could not commit transaction", err) return types.ErrInternal } @@ -243,7 +243,7 @@ func (db AuthDbSqlite) InsertToken(token *Token) error { VALUES (?, ?, ?, ?, ?)`, token.UserId, token.Type, token.Token, token.CreatedAt, token.ExpiresAt) if err != nil { - utils.LogError("Could not insert token", err) + log.Error("Could not insert token", err) return types.ErrInternal } @@ -271,20 +271,20 @@ func (db AuthDbSqlite) GetToken(token string) (*Token, error) { slog.Info("Token '" + token + "' not found") return nil, ErrNotFound } else { - utils.LogError("Could not get token", err) + log.Error("Could not get token", err) return nil, types.ErrInternal } } createdAt, err = time.Parse(time.RFC3339, createdAtStr) if err != nil { - utils.LogError("Could not parse token.created_at", err) + log.Error("Could not parse token.created_at", err) return nil, types.ErrInternal } expiresAt, err = time.Parse(time.RFC3339, expiresAtStr) if err != nil { - utils.LogError("Could not parse token.expires_at", err) + log.Error("Could not parse token.expires_at", err) return nil, types.ErrInternal } @@ -300,7 +300,7 @@ func (db AuthDbSqlite) GetTokensByUserIdAndType(userId uuid.UUID, tokenType stri AND type = ?`, userId, tokenType) if err != nil { - utils.LogError("Could not get token", err) + log.Error("Could not get token", err) return nil, types.ErrInternal } @@ -317,19 +317,19 @@ func (db AuthDbSqlite) GetTokensByUserIdAndType(userId uuid.UUID, tokenType stri err := query.Scan(&token, &createdAtStr, &expiresAtStr) if err != nil { - utils.LogError("Could not scan token", err) + log.Error("Could not scan token", err) return nil, types.ErrInternal } createdAt, err = time.Parse(time.RFC3339, createdAtStr) if err != nil { - utils.LogError("Could not parse token.created_at", err) + log.Error("Could not parse token.created_at", err) return nil, types.ErrInternal } expiresAt, err = time.Parse(time.RFC3339, expiresAtStr) if err != nil { - utils.LogError("Could not parse token.expires_at", err) + log.Error("Could not parse token.expires_at", err) return nil, types.ErrInternal } @@ -342,7 +342,7 @@ func (db AuthDbSqlite) GetTokensByUserIdAndType(userId uuid.UUID, tokenType stri func (db AuthDbSqlite) DeleteToken(token string) error { _, err := db.db.Exec("DELETE FROM user_token WHERE token = ?", token) if err != nil { - utils.LogError("Could not delete token", err) + log.Error("Could not delete token", err) return types.ErrInternal } return nil @@ -355,7 +355,7 @@ func (db AuthDbSqlite) InsertSession(session *Session) error { VALUES (?, ?, ?)`, session.Id, session.UserId, session.CreatedAt) if err != nil { - utils.LogError("Could not insert new session", err) + log.Error("Could not insert new session", err) return types.ErrInternal } @@ -386,7 +386,7 @@ func (db AuthDbSqlite) DeleteOldSessions(userId uuid.UUID) error { // Delete old inactive sessions _, err := db.db.Exec("DELETE FROM session WHERE created_at < datetime('now','-8 hours') AND user_uuid = ?", userId) if err != nil { - utils.LogError("Could not delete old sessions", err) + log.Error("Could not delete old sessions", err) return types.ErrInternal } return nil @@ -397,7 +397,7 @@ func (db AuthDbSqlite) DeleteSession(sessionId string) error { _, err := db.db.Exec("DELETE FROM session WHERE session_id = ?", sessionId) if err != nil { - utils.LogError("Could not delete session", err) + log.Error("Could not delete session", err) return types.ErrInternal } } diff --git a/db/workout.go b/db/workout.go index 5067398..55c628b 100644 --- a/db/workout.go +++ b/db/workout.go @@ -1,8 +1,8 @@ package db import ( + "me-fit/log" "me-fit/types" - "me-fit/utils" "database/sql" "errors" @@ -59,7 +59,7 @@ func (db WorkoutDbSqlite) InsertWorkout(userId uuid.UUID, workout *WorkoutInsert VALUES (?, ?, ?, ?, ?) RETURNING rowid`, userId, workout.Date, workout.Type, workout.Sets, workout.Reps).Scan(&rowId) if err != nil { - utils.LogError("Error inserting workout", err) + log.Error("Error inserting workout", err) return nil, types.ErrInternal } @@ -70,7 +70,7 @@ func (db WorkoutDbSqlite) GetWorkouts(userId uuid.UUID) ([]Workout, error) { rows, err := db.db.Query("SELECT rowid, date, type, sets, reps FROM workout WHERE user_id = ? ORDER BY date desc", userId) if err != nil { - utils.LogError("Could not get workouts", err) + log.Error("Could not get workouts", err) return nil, types.ErrInternal } @@ -83,13 +83,13 @@ func (db WorkoutDbSqlite) GetWorkouts(userId uuid.UUID) ([]Workout, error) { err = rows.Scan(&workout.RowId, &date, &workout.Type, &workout.Sets, &workout.Reps) if err != nil { - utils.LogError("Could not scan workout", err) + log.Error("Could not scan workout", err) return nil, types.ErrInternal } workout.Date, err = time.Parse("2006-01-02 15:04:05-07:00", date) if err != nil { - utils.LogError("Could not parse date", err) + log.Error("Could not parse date", err) return nil, types.ErrInternal } diff --git a/handler/auth.go b/handler/auth.go index ecf9b7b..acd16b3 100644 --- a/handler/auth.go +++ b/handler/auth.go @@ -1,6 +1,7 @@ package handler import ( + "me-fit/log" "me-fit/service" "me-fit/template/auth" "me-fit/types" @@ -29,16 +30,15 @@ func NewHandlerAuth(service service.AuthService, render *Render) HandlerAuth { } 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("/api/auth/signin", handler.handleSignIn()) + router.Handle("/auth/signup", handler.handleSignUpPage()) 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()) @@ -105,7 +105,7 @@ func (handler HandlerAuthImpl) handleSignIn() http.HandlerFunc { utils.TriggerToast(w, r, "error", "Invalid email or password") http.Error(w, "Invalid email or password", http.StatusUnauthorized) } else { - utils.LogError("Error signing in", err) + log.Error("Error signing in", err) http.Error(w, "An error occurred", http.StatusInternalServerError) } return @@ -305,7 +305,7 @@ func (handler HandlerAuthImpl) HandleVerifyResendComp() http.HandlerFunc { _, err = w.Write([]byte("
Verification email sent
")) if err != nil { - utils.LogError("Could not write response", err) + log.Error("Could not write response", err) } } } @@ -370,7 +370,7 @@ func (handler HandlerAuthImpl) HandleForgotPasswordResponseComp() http.HandlerFu pageUrl, err := url.Parse(r.Header.Get("HX-Current-URL")) if err != nil { - utils.LogError("Could not get current URL", err) + log.Error("Could not get current URL", err) utils.TriggerToast(w, r, "error", "Internal Server Error") return } diff --git a/handler/render.go b/handler/render.go index 56d2227..a687168 100644 --- a/handler/render.go +++ b/handler/render.go @@ -1,11 +1,11 @@ package handler import ( + "me-fit/log" "me-fit/service" "me-fit/template" "me-fit/template/auth" "me-fit/types" - "me-fit/utils" "net/http" @@ -25,7 +25,7 @@ func NewRender(serverSettings *types.ServerSettings) *Render { 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) + log.Error("Failed to render layout", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } } diff --git a/log/default.go b/log/default.go new file mode 100644 index 0000000..e4576a2 --- /dev/null +++ b/log/default.go @@ -0,0 +1,26 @@ +package log + +import ( + "log/slog" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + errorMetric = promauto.NewCounter( + prometheus.CounterOpts{ + Name: "mefit_error_total", + Help: "The total number of errors during processing", + }, + ) +) + +func Error(message string, err error) { + slog.Error(message + ": " + err.Error()) + errorMetric.Inc() +} +func ErrorMsg(message string) { + slog.Error(message) + errorMetric.Inc() +} diff --git a/service/auth.go b/service/auth.go index a53077b..cc1d1df 100644 --- a/service/auth.go +++ b/service/auth.go @@ -9,9 +9,9 @@ import ( "time" "me-fit/db" + "me-fit/log" mailTemplate "me-fit/template/mail" "me-fit/types" - "me-fit/utils" "github.com/google/uuid" "golang.org/x/crypto/argon2" @@ -201,7 +201,7 @@ func (service AuthServiceImpl) SendVerificationMail(userId uuid.UUID, email stri var w strings.Builder err = mailTemplate.Register(service.serverSettings.BaseUrl, token.Token).Render(context.Background(), &w) if err != nil { - utils.LogError("Could not render welcome email", err) + log.Error("Could not render welcome email", err) return } @@ -343,7 +343,7 @@ func (service AuthServiceImpl) SendForgotPasswordMail(email string) error { var mail strings.Builder err = mailTemplate.ResetPassword(service.serverSettings.BaseUrl, token.Token).Render(context.Background(), &mail) if err != nil { - utils.LogError("Could not render reset password email", err) + log.Error("Could not render reset password email", err) return types.ErrInternal } go service.mailService.SendMail(email, "Reset Password", mail.String()) @@ -369,7 +369,7 @@ func (service AuthServiceImpl) ForgotPassword(tokenStr string, newPass string) e user, err := service.dbAuth.GetUser(token.UserId) if err != nil { - utils.LogError("Could not get user from token", err) + log.Error("Could not get user from token", err) return types.ErrInternal } diff --git a/service/mail.go b/service/mail.go index 08b6fe2..b8ee841 100644 --- a/service/mail.go +++ b/service/mail.go @@ -1,11 +1,11 @@ package service import ( + "me-fit/log" + "me-fit/types" + "fmt" "net/smtp" - - "me-fit/types" - "me-fit/utils" ) type MailService interface { @@ -34,6 +34,6 @@ func (m MailServiceImpl) SendMail(to string, subject string, message string) { err := smtp.SendMail(s.Host+":"+s.Port, auth, s.FromMail, []string{to}, []byte(msg)) if err != nil { - utils.LogError("Error sending mail: %v", err) + log.Error("Error sending mail: %v", err) } } diff --git a/utils/http.go b/utils/http.go index 64ff202..7178a49 100644 --- a/utils/http.go +++ b/utils/http.go @@ -1,44 +1,18 @@ package utils import ( + "me-fit/log" + "fmt" - "log/slog" "net/http" "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" ) -type ContextKey string - -const ( - ContextKeyUser ContextKey = "user_id" -) - -var ( - errorMetric = promauto.NewCounter( - prometheus.CounterOpts{ - Name: "mefit_error_total", - Help: "The total number of errors during processing", - }, - ) -) - -func LogError(message string, err error) { - slog.Error(message + ": " + err.Error()) - errorMetric.Inc() -} -func LogErrorMsg(message string) { - slog.Error(message) - errorMetric.Inc() -} - func TriggerToast(w http.ResponseWriter, r *http.Request, class string, message string) { if isHtmx(r) { w.Header().Set("HX-Trigger", fmt.Sprintf(`{"toast": "%v|%v"}`, class, message)) } else { - LogErrorMsg("Trying to trigger toast in non-HTMX request") + log.ErrorMsg("Trying to trigger toast in non-HTMX request") } }