diff --git a/go.mod b/go.mod index e0ffecc..c773ded 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module git.t-juice.club/microfilm/users -go 1.21 +go 1.21.3 require ( github.com/go-chi/chi/v5 v5.0.10 diff --git a/go.sum b/go.sum index e54c58a..86043e2 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,12 @@ +git.t-juice.club/microfilm/auth v0.1.1 h1:usg48CEd94Ha2rkEdCU+mhczJvLwwxVouOl478YdZFE= +git.t-juice.club/microfilm/auth v0.1.1/go.mod h1:sfgaIWxnNgERWyx611596OtEBc3cF4g3FSqKd073Te4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= diff --git a/server/middleware.go b/server/middleware.go new file mode 100644 index 0000000..4803618 --- /dev/null +++ b/server/middleware.go @@ -0,0 +1,25 @@ +package server + +import ( + "net/http" + "time" + + "github.com/go-chi/chi/v5/middleware" +) + +func (s *UserServer) MiddlewareLogging(next http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) + + t1 := time.Now() + defer func(ww middleware.WrapResponseWriter) { + s.Logger.Info("Served request.", + "status", ww.Status(), + "path", r.URL.Path, + "duration", time.Since(t1), + "written", ww.BytesWritten()) + }(ww) + next.ServeHTTP(ww, r) + } + return http.HandlerFunc(fn) +} diff --git a/server/server.go b/server/server.go index e1715c3..bedf289 100644 --- a/server/server.go +++ b/server/server.go @@ -20,7 +20,7 @@ type UserServer struct { store store.UserStore config *Config nats *nats.Conn - logger *slog.Logger + Logger *slog.Logger } func NewServer(config *Config) (*UserServer, error) { @@ -28,14 +28,16 @@ func NewServer(config *Config) (*UserServer, error) { srv := &UserServer{} srv.config = config - srv.logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + srv.Logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ Level: slog.LevelDebug, })) - r.Get("/", InfoHandler) - r.Post("/users", srv.CreateUserHandler) - r.Post("/users/:id/password", srv.SetPasswordHandler) - r.Post("/users/:username/verify", srv.VerifyHandler) + r.Use(srv.MiddlewareLogging) + + r.Get("/info", InfoHandler) + r.Post("/", srv.CreateUserHandler) + r.Post("/{identifier}/password", srv.SetPasswordHandler) + r.Post("/{identifier}/verify", srv.VerifyHandler) srv.Addr = config.ListenAddr @@ -63,8 +65,9 @@ func InfoHandler(w http.ResponseWriter, r *http.Request) { } func WriteError(w http.ResponseWriter, response users.ErrorResponse) { - encoder := json.NewEncoder(w) w.WriteHeader(response.Status) + + encoder := json.NewEncoder(w) _ = encoder.Encode(&response) } @@ -97,7 +100,7 @@ func (s *UserServer) CreateUserHandler(w http.ResponseWriter, r *http.Request) { } if err := s.store.AddUser(u); err != nil { - s.logger.Warn("Error storing user", "error", err) + s.Logger.Warn("Error storing user", "error", err) WriteError(w, users.ErrorResponse{ Status: http.StatusInternalServerError, Message: fmt.Sprintf("Error storing user: %s", err), @@ -116,10 +119,10 @@ func (s *UserServer) CreateUserHandler(w http.ResponseWriter, r *http.Request) { encoder := json.NewEncoder(&buf) _ = encoder.Encode(&msg) if err := s.nats.Publish(sub, buf.Bytes()); err != nil { - s.logger.Warn("Error publishing message", "error", err) + s.Logger.Warn("Error publishing message", "error", err) } - s.logger.Info("User created.", "username", u.Username, "id", u.ID) + s.Logger.Info("User created.", "username", u.Username, "id", u.ID) response := &users.CreateUserResponse{ Message: "User created.", @@ -144,12 +147,13 @@ func (s *UserServer) SetPasswordHandler(w http.ResponseWriter, r *http.Request) return } - id := chi.URLParam(r, "id") + id := chi.URLParam(r, "identifier") if id == "" { WriteError(w, users.ErrorResponse{ Status: http.StatusBadRequest, Message: fmt.Sprintf("Invalid user ID: %s", id), }) + return } u, err := s.store.GetUser(id) @@ -175,14 +179,16 @@ func (s *UserServer) SetPasswordHandler(w http.ResponseWriter, r *http.Request) Status: http.StatusBadRequest, Message: fmt.Sprintf("Unable to set password: %s", id), }) + return } if err := s.store.UpdateUser(u); err != nil { - s.logger.Warn("Unable to update user.", "id", u.ID, "error", err) + s.Logger.Warn("Unable to update user.", "id", u.ID, "error", err) WriteError(w, users.ErrorResponse{ Status: http.StatusInternalServerError, Message: fmt.Sprintf("Unable to set password: %s", id), }) + return } sub := fmt.Sprintf("%s.%s", s.config.NATSSubject, "update") @@ -191,9 +197,9 @@ func (s *UserServer) SetPasswordHandler(w http.ResponseWriter, r *http.Request) _ = encoder.Encode(&users.MsgUserUpdate{Message: "Password updated", ID: u.ID}) if err := s.nats.Publish(sub, buf.Bytes()); err != nil { - s.logger.Warn("Error publishing message", "error", err) + s.Logger.Warn("Error publishing message", "error", err) } - s.logger.Info("User password updated.", "id", u.ID) + s.Logger.Info("User password updated.", "id", u.ID) } func (s *UserServer) VerifyHandler(w http.ResponseWriter, r *http.Request) { @@ -210,12 +216,13 @@ func (s *UserServer) VerifyHandler(w http.ResponseWriter, r *http.Request) { return } - id := chi.URLParam(r, "id") + id := chi.URLParam(r, "identifier") if id == "" { WriteError(w, users.ErrorResponse{ Status: http.StatusBadRequest, Message: fmt.Sprintf("Invalid user ID: %s", id), }) + return } u, err := s.store.GetUser(id) @@ -242,5 +249,7 @@ func (s *UserServer) VerifyHandler(w http.ResponseWriter, r *http.Request) { Status: http.StatusUnauthorized, Message: "Password verification failed.", }) + return } + w.WriteHeader(http.StatusOK) }