mirror of
https://github.com/miniflux/v2.git
synced 2025-09-15 18:57:04 +00:00
Implement structured logging using log/slog package
This commit is contained in:
parent
54cb8fa028
commit
c0e954f19d
77 changed files with 1868 additions and 892 deletions
|
@ -9,14 +9,14 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
)
|
||||
|
||||
func (h *handler) removeAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
keyID := request.RouteInt64Param(r, "keyID")
|
||||
err := h.store.RemoveAPIKey(request.UserID(r), keyID)
|
||||
if err != nil {
|
||||
logger.Error("[UI:RemoveAPIKey] %v", err)
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
html.Redirect(w, r, route.Path(h.router, "apiKeys"))
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
"miniflux.app/v2/internal/ui/form"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
|
@ -47,9 +46,7 @@ func (h *handler) saveAPIKey(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
apiKey := model.NewAPIKey(user.ID, apiKeyForm.Description)
|
||||
if err = h.store.CreateAPIKey(apiKey); err != nil {
|
||||
logger.Error("[UI:SaveAPIKey] %v", err)
|
||||
view.Set("errorMessage", "error.unable_to_create_api_key")
|
||||
html.OK(w, r, view.Render("create_api_key"))
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
"miniflux.app/v2/internal/ui/form"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
|
@ -43,9 +42,7 @@ func (h *handler) saveCategory(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if _, err = h.store.CreateCategory(loggedUser.ID, categoryRequest); err != nil {
|
||||
logger.Error("[UI:SaveCategory] %v", err)
|
||||
view.Set("errorMessage", "error.unable_to_create_category")
|
||||
html.OK(w, r, view.Render("create_category"))
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
"miniflux.app/v2/internal/ui/form"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
|
@ -60,9 +59,7 @@ func (h *handler) updateCategory(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
categoryRequest.Patch(category)
|
||||
if err := h.store.UpdateCategory(category); err != nil {
|
||||
logger.Error("[UI:UpdateCategory] %v", err)
|
||||
view.Set("errorMessage", "error.unable_to_update_category")
|
||||
html.OK(w, r, view.Render("edit_category"))
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
package ui // import "miniflux.app/v2/internal/ui"
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
feedHandler "miniflux.app/v2/internal/reader/handler"
|
||||
)
|
||||
|
||||
|
@ -17,7 +17,12 @@ func (h *handler) refreshFeed(w http.ResponseWriter, r *http.Request) {
|
|||
feedID := request.RouteInt64Param(r, "feedID")
|
||||
forceRefresh := request.QueryBoolParam(r, "forceRefresh", false)
|
||||
if err := feedHandler.RefreshFeed(h.store, request.UserID(r), feedID, forceRefresh); err != nil {
|
||||
logger.Error("[UI:RefreshFeed] %v", err)
|
||||
slog.Warn("Unable to refresh feed",
|
||||
slog.Int64("user_id", request.UserID(r)),
|
||||
slog.Int64("feed_id", feedID),
|
||||
slog.Bool("force_refresh", forceRefresh),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
}
|
||||
|
||||
html.Redirect(w, r, route.Path(h.router, "feedEntries", "feedID", feedID))
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
"miniflux.app/v2/internal/ui/form"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
|
@ -74,9 +73,7 @@ func (h *handler) updateFeed(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
err = h.store.UpdateFeed(feedForm.Merge(feed))
|
||||
if err != nil {
|
||||
logger.Error("[UI:UpdateFeed] %v", err)
|
||||
view.Set("errorMessage", "error.unable_to_update_feed")
|
||||
html.OK(w, r, view.Render("edit_feed"))
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package ui // import "miniflux.app/v2/internal/ui"
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/config"
|
||||
|
@ -12,7 +13,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/integration/pocket"
|
||||
"miniflux.app/v2/internal/locale"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
)
|
||||
|
||||
|
@ -35,7 +35,10 @@ func (h *handler) pocketAuthorize(w http.ResponseWriter, r *http.Request) {
|
|||
redirectURL := config.Opts.RootURL() + route.Path(h.router, "pocketCallback")
|
||||
requestToken, err := connector.RequestToken(redirectURL)
|
||||
if err != nil {
|
||||
logger.Error("[Pocket:Authorize] %v", err)
|
||||
slog.Warn("Pocket authorization request failed",
|
||||
slog.Any("user_id", user.ID),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
sess.NewFlashErrorMessage(printer.Printf("error.pocket_request_token"))
|
||||
html.Redirect(w, r, route.Path(h.router, "integrations"))
|
||||
return
|
||||
|
@ -64,7 +67,10 @@ func (h *handler) pocketCallback(w http.ResponseWriter, r *http.Request) {
|
|||
connector := pocket.NewConnector(config.Opts.PocketConsumerKey(integration.PocketConsumerKey))
|
||||
accessToken, err := connector.AccessToken(request.PocketRequestToken(r))
|
||||
if err != nil {
|
||||
logger.Error("[Pocket:Callback] %v", err)
|
||||
slog.Warn("Unable to get Pocket access token",
|
||||
slog.Any("user_id", user.ID),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
sess.NewFlashErrorMessage(printer.Printf("error.pocket_access_token"))
|
||||
html.Redirect(w, r, route.Path(h.router, "integrations"))
|
||||
return
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package ui // import "miniflux.app/v2/internal/ui"
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/config"
|
||||
|
@ -11,7 +12,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/ui/form"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
"miniflux.app/v2/internal/ui/view"
|
||||
|
@ -27,13 +27,25 @@ func (h *handler) checkLogin(w http.ResponseWriter, r *http.Request) {
|
|||
view.Set("form", authForm)
|
||||
|
||||
if err := authForm.Validate(); err != nil {
|
||||
logger.Error("[UI:CheckLogin] %v", err)
|
||||
slog.Warn("Validation error during login check",
|
||||
slog.Bool("authentication_failed", true),
|
||||
slog.String("client_ip", clientIP),
|
||||
slog.String("user_agent", r.UserAgent()),
|
||||
slog.String("username", authForm.Username),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
html.OK(w, r, view.Render("login"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.store.CheckPassword(authForm.Username, authForm.Password); err != nil {
|
||||
logger.Error("[UI:CheckLogin] [ClientIP=%s] %v", clientIP, err)
|
||||
slog.Warn("Incorrect username or password",
|
||||
slog.Bool("authentication_failed", true),
|
||||
slog.String("client_ip", clientIP),
|
||||
slog.String("user_agent", r.UserAgent()),
|
||||
slog.String("username", authForm.Username),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
html.OK(w, r, view.Render("login"))
|
||||
return
|
||||
}
|
||||
|
@ -44,7 +56,14 @@ func (h *handler) checkLogin(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
logger.Info("[UI:CheckLogin] username=%s just logged in", authForm.Username)
|
||||
slog.Info("User authenticated successfully with username/password",
|
||||
slog.Bool("authentication_successful", true),
|
||||
slog.String("client_ip", clientIP),
|
||||
slog.String("user_agent", r.UserAgent()),
|
||||
slog.Int64("user_id", userID),
|
||||
slog.String("username", authForm.Username),
|
||||
)
|
||||
|
||||
h.store.SetLastLogin(userID)
|
||||
|
||||
user, err := h.store.UserByID(userID)
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
)
|
||||
|
||||
|
@ -27,7 +26,8 @@ func (h *handler) logout(w http.ResponseWriter, r *http.Request) {
|
|||
sess.SetTheme(user.Theme)
|
||||
|
||||
if err := h.store.RemoveUserSessionByToken(user.ID, request.UserSessionToken(r)); err != nil {
|
||||
logger.Error("[UI:Logout] %v", err)
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
http.SetCookie(w, cookie.Expired(
|
||||
|
|
|
@ -6,6 +6,7 @@ package ui // import "miniflux.app/v2/internal/ui"
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/config"
|
||||
|
@ -13,7 +14,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
"miniflux.app/v2/internal/storage"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
|
@ -38,11 +38,17 @@ func (m *middleware) handleUserSession(next http.Handler) http.Handler {
|
|||
if m.isPublicRoute(r) {
|
||||
next.ServeHTTP(w, r)
|
||||
} else {
|
||||
logger.Debug("[UI:UserSession] Session not found, redirect to login page")
|
||||
slog.Debug("Redirecting to login page because no user session has been found",
|
||||
slog.Any("url", r.RequestURI),
|
||||
)
|
||||
html.Redirect(w, r, route.Path(m.router, "login"))
|
||||
}
|
||||
} else {
|
||||
logger.Debug("[UI:UserSession] %s", session)
|
||||
slog.Debug("User session found",
|
||||
slog.Any("url", r.RequestURI),
|
||||
slog.Int64("user_id", session.UserID),
|
||||
slog.Int64("user_session_id", session.ID),
|
||||
)
|
||||
|
||||
ctx := r.Context()
|
||||
ctx = context.WithValue(ctx, request.UserIDContextKey, session.UserID)
|
||||
|
@ -62,14 +68,16 @@ func (m *middleware) handleAppSession(next http.Handler) http.Handler {
|
|||
if session == nil {
|
||||
if request.IsAuthenticated(r) {
|
||||
userID := request.UserID(r)
|
||||
logger.Debug("[UI:AppSession] Cookie expired but user #%d is logged: creating a new session", userID)
|
||||
slog.Debug("Cookie expired but user is logged: creating a new app session",
|
||||
slog.Int64("user_id", userID),
|
||||
)
|
||||
session, err = m.store.CreateAppSessionWithUserPrefs(userID)
|
||||
if err != nil {
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
logger.Debug("[UI:AppSession] Session not found, creating a new one")
|
||||
slog.Debug("App session not found, creating a new one")
|
||||
session, err = m.store.CreateAppSession()
|
||||
if err != nil {
|
||||
html.ServerError(w, r, err)
|
||||
|
@ -78,8 +86,6 @@ func (m *middleware) handleAppSession(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
http.SetCookie(w, cookie.New(cookie.CookieAppSessionID, session.ID, config.Opts.HTTPS, config.Opts.BasePath()))
|
||||
} else {
|
||||
logger.Debug("[UI:AppSession] %s", session)
|
||||
}
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
|
@ -87,7 +93,11 @@ func (m *middleware) handleAppSession(next http.Handler) http.Handler {
|
|||
headerValue := r.Header.Get("X-Csrf-Token")
|
||||
|
||||
if session.Data.CSRF != formValue && session.Data.CSRF != headerValue {
|
||||
logger.Error(`[UI:AppSession] Invalid or missing CSRF token: Form="%s", Header="%s"`, formValue, headerValue)
|
||||
slog.Warn("Invalid or missing CSRF token",
|
||||
slog.Any("url", r.RequestURI),
|
||||
slog.String("form_csrf", formValue),
|
||||
slog.String("header_csrf", headerValue),
|
||||
)
|
||||
|
||||
if mux.CurrentRoute(r).GetName() == "checkLogin" {
|
||||
html.Redirect(w, r, route.Path(m.router, "login"))
|
||||
|
@ -121,7 +131,10 @@ func (m *middleware) getAppSessionValueFromCookie(r *http.Request) *model.Sessio
|
|||
|
||||
session, err := m.store.AppSession(cookieValue)
|
||||
if err != nil {
|
||||
logger.Error("[UI:AppSession] %v", err)
|
||||
slog.Debug("Unable to fetch app session from the database; another session will be created",
|
||||
slog.Any("cookie_value", cookieValue),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -159,7 +172,10 @@ func (m *middleware) getUserSessionFromCookie(r *http.Request) *model.UserSessio
|
|||
|
||||
session, err := m.store.UserSessionByToken(cookieValue)
|
||||
if err != nil {
|
||||
logger.Error("[UI:UserSession] %v", err)
|
||||
slog.Error("Unable to fetch user session from the database",
|
||||
slog.Any("cookie_value", cookieValue),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -180,7 +196,11 @@ func (m *middleware) handleAuthProxy(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
clientIP := request.ClientIP(r)
|
||||
logger.Info("[AuthProxy] [ClientIP=%s] Received authenticated requested for %q", clientIP, username)
|
||||
slog.Debug("[AuthProxy] Received authenticated requested",
|
||||
slog.String("client_ip", clientIP),
|
||||
slog.String("user_agent", r.UserAgent()),
|
||||
slog.String("username", username),
|
||||
)
|
||||
|
||||
user, err := m.store.UserByUsername(username)
|
||||
if err != nil {
|
||||
|
@ -189,9 +209,13 @@ func (m *middleware) handleAuthProxy(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
if user == nil {
|
||||
logger.Error("[AuthProxy] [ClientIP=%s] %q doesn't exist", clientIP, username)
|
||||
|
||||
if !config.Opts.IsAuthProxyUserCreationAllowed() {
|
||||
slog.Debug("[AuthProxy] User doesn't exist and user creation is not allowed",
|
||||
slog.Bool("authentication_failed", true),
|
||||
slog.String("client_ip", clientIP),
|
||||
slog.String("user_agent", r.UserAgent()),
|
||||
slog.String("username", username),
|
||||
)
|
||||
html.Forbidden(w, r)
|
||||
return
|
||||
}
|
||||
|
@ -208,7 +232,13 @@ func (m *middleware) handleAuthProxy(next http.Handler) http.Handler {
|
|||
return
|
||||
}
|
||||
|
||||
logger.Info("[AuthProxy] [ClientIP=%s] username=%s just logged in", clientIP, user.Username)
|
||||
slog.Info("[AuthProxy] User authenticated successfully",
|
||||
slog.Bool("authentication_successful", true),
|
||||
slog.String("client_ip", clientIP),
|
||||
slog.String("user_agent", r.UserAgent()),
|
||||
slog.Int64("user_id", user.ID),
|
||||
slog.String("username", user.Username),
|
||||
)
|
||||
|
||||
m.store.SetLastLogin(user.ID)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ package ui // import "miniflux.app/v2/internal/ui"
|
|||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/config"
|
||||
|
@ -14,7 +15,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/locale"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
)
|
||||
|
@ -26,41 +26,48 @@ func (h *handler) oauth2Callback(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
provider := request.RouteStringParam(r, "provider")
|
||||
if provider == "" {
|
||||
logger.Error("[OAuth2] Invalid or missing provider")
|
||||
slog.Warn("Invalid or missing OAuth2 provider")
|
||||
html.Redirect(w, r, route.Path(h.router, "login"))
|
||||
return
|
||||
}
|
||||
|
||||
code := request.QueryStringParam(r, "code", "")
|
||||
if code == "" {
|
||||
logger.Error("[OAuth2] No code received on callback")
|
||||
slog.Warn("No code received on OAuth2 callback")
|
||||
html.Redirect(w, r, route.Path(h.router, "login"))
|
||||
return
|
||||
}
|
||||
|
||||
state := request.QueryStringParam(r, "state", "")
|
||||
if subtle.ConstantTimeCompare([]byte(state), []byte(request.OAuth2State(r))) == 0 {
|
||||
logger.Error(`[OAuth2] Invalid state value: got "%s" instead of "%s"`, state, request.OAuth2State(r))
|
||||
slog.Warn("Invalid OAuth2 state value received",
|
||||
slog.String("expected", request.OAuth2State(r)),
|
||||
slog.String("received", state),
|
||||
)
|
||||
html.Redirect(w, r, route.Path(h.router, "login"))
|
||||
return
|
||||
}
|
||||
|
||||
authProvider, err := getOAuth2Manager(r.Context()).FindProvider(provider)
|
||||
if err != nil {
|
||||
logger.Error("[OAuth2] %v", err)
|
||||
slog.Error("Unable to initialize OAuth2 provider",
|
||||
slog.String("provider", provider),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
html.Redirect(w, r, route.Path(h.router, "login"))
|
||||
return
|
||||
}
|
||||
|
||||
profile, err := authProvider.GetProfile(r.Context(), code, request.OAuth2CodeVerifier(r))
|
||||
if err != nil {
|
||||
logger.Error("[OAuth2] %v", err)
|
||||
slog.Warn("Unable to get OAuth2 profile from provider",
|
||||
slog.String("provider", provider),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
html.Redirect(w, r, route.Path(h.router, "login"))
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("[OAuth2] [ClientIP=%s] Successful auth for %s", clientIP, profile)
|
||||
|
||||
if request.IsAuthenticated(r) {
|
||||
loggedUser, err := h.store.UserByID(request.UserID(r))
|
||||
if err != nil {
|
||||
|
@ -69,7 +76,11 @@ func (h *handler) oauth2Callback(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if h.store.AnotherUserWithFieldExists(loggedUser.ID, profile.Key, profile.ID) {
|
||||
logger.Error("[OAuth2] User #%d cannot be associated because it is already associated with another user", loggedUser.ID)
|
||||
slog.Error("Oauth2 user cannot be associated because it is already associated with another user",
|
||||
slog.Int64("user_id", loggedUser.ID),
|
||||
slog.String("oauth2_provider", provider),
|
||||
slog.String("oauth2_profile_id", profile.ID),
|
||||
)
|
||||
sess.NewFlashErrorMessage(printer.Printf("error.duplicate_linked_account"))
|
||||
html.Redirect(w, r, route.Path(h.router, "settings"))
|
||||
return
|
||||
|
@ -119,7 +130,13 @@ func (h *handler) oauth2Callback(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
logger.Info("[OAuth2] [ClientIP=%s] username=%s (%s) just logged in", clientIP, user.Username, profile)
|
||||
slog.Info("User authenticated successfully using OAuth2",
|
||||
slog.Bool("authentication_successful", true),
|
||||
slog.String("client_ip", clientIP),
|
||||
slog.String("user_agent", r.UserAgent()),
|
||||
slog.Int64("user_id", user.ID),
|
||||
slog.String("username", user.Username),
|
||||
)
|
||||
|
||||
h.store.SetLastLogin(user.ID)
|
||||
sess.SetLanguage(user.Language)
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
package ui // import "miniflux.app/v2/internal/ui"
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/oauth2"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
)
|
||||
|
@ -19,14 +19,17 @@ func (h *handler) oauth2Redirect(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
provider := request.RouteStringParam(r, "provider")
|
||||
if provider == "" {
|
||||
logger.Error("[OAuth2] Invalid or missing provider: %s", provider)
|
||||
slog.Warn("Invalid or missing OAuth2 provider")
|
||||
html.Redirect(w, r, route.Path(h.router, "login"))
|
||||
return
|
||||
}
|
||||
|
||||
authProvider, err := getOAuth2Manager(r.Context()).FindProvider(provider)
|
||||
if err != nil {
|
||||
logger.Error("[OAuth2] %v", err)
|
||||
slog.Error("Unable to initialize OAuth2 provider",
|
||||
slog.String("provider", provider),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
html.Redirect(w, r, route.Path(h.router, "login"))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
package ui // import "miniflux.app/v2/internal/ui"
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/locale"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
)
|
||||
|
||||
|
@ -18,14 +18,17 @@ func (h *handler) oauth2Unlink(w http.ResponseWriter, r *http.Request) {
|
|||
printer := locale.NewPrinter(request.UserLanguage(r))
|
||||
provider := request.RouteStringParam(r, "provider")
|
||||
if provider == "" {
|
||||
logger.Info("[OAuth2] Invalid or missing provider")
|
||||
slog.Warn("Invalid or missing OAuth2 provider")
|
||||
html.Redirect(w, r, route.Path(h.router, "login"))
|
||||
return
|
||||
}
|
||||
|
||||
authProvider, err := getOAuth2Manager(r.Context()).FindProvider(provider)
|
||||
if err != nil {
|
||||
logger.Error("[OAuth2] %v", err)
|
||||
slog.Error("Unable to initialize OAuth2 provider",
|
||||
slog.String("provider", provider),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
html.Redirect(w, r, route.Path(h.router, "settings"))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package ui // import "miniflux.app/v2/internal/ui"
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/config"
|
||||
|
@ -11,14 +12,14 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/reader/opml"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
"miniflux.app/v2/internal/ui/view"
|
||||
)
|
||||
|
||||
func (h *handler) uploadOPML(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := h.store.UserByID(request.UserID(r))
|
||||
loggedUserID := request.UserID(r)
|
||||
user, err := h.store.UserByID(loggedUserID)
|
||||
if err != nil {
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
|
@ -26,17 +27,20 @@ func (h *handler) uploadOPML(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
file, fileHeader, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
logger.Error("[UI:UploadOPML] %v", err)
|
||||
slog.Error("OPML file upload error",
|
||||
slog.Int64("user_id", loggedUserID),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
|
||||
html.Redirect(w, r, route.Path(h.router, "import"))
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
logger.Debug(
|
||||
"[UI:UploadOPML] User #%d uploaded this file: %s (%d bytes)",
|
||||
user.ID,
|
||||
fileHeader.Filename,
|
||||
fileHeader.Size,
|
||||
slog.Info("OPML file uploaded",
|
||||
slog.Int64("user_id", loggedUserID),
|
||||
slog.String("file_name", fileHeader.Filename),
|
||||
slog.Int64("file_size", fileHeader.Size),
|
||||
)
|
||||
|
||||
sess := session.New(h.store, request.SessionID(r))
|
||||
|
@ -62,7 +66,8 @@ func (h *handler) uploadOPML(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func (h *handler) fetchOPML(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := h.store.UserByID(request.UserID(r))
|
||||
loggedUserID := request.UserID(r)
|
||||
user, err := h.store.UserByID(loggedUserID)
|
||||
if err != nil {
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
|
@ -74,10 +79,9 @@ func (h *handler) fetchOPML(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
logger.Debug(
|
||||
"[UI:FetchOPML] User #%d fetching this URL: %s",
|
||||
user.ID,
|
||||
url,
|
||||
slog.Info("Fetching OPML file remotely",
|
||||
slog.Int64("user_id", loggedUserID),
|
||||
slog.String("opml_file_url", url),
|
||||
)
|
||||
|
||||
sess := session.New(h.store, request.SessionID(r))
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
|
@ -16,7 +17,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
)
|
||||
|
||||
func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -29,19 +29,19 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) {
|
|||
encodedDigest := request.RouteStringParam(r, "encodedDigest")
|
||||
encodedURL := request.RouteStringParam(r, "encodedURL")
|
||||
if encodedURL == "" {
|
||||
html.BadRequest(w, r, errors.New("No URL provided"))
|
||||
html.BadRequest(w, r, errors.New("no URL provided"))
|
||||
return
|
||||
}
|
||||
|
||||
decodedDigest, err := base64.URLEncoding.DecodeString(encodedDigest)
|
||||
if err != nil {
|
||||
html.BadRequest(w, r, errors.New("Unable to decode this Digest"))
|
||||
html.BadRequest(w, r, errors.New("unable to decode this digest"))
|
||||
return
|
||||
}
|
||||
|
||||
decodedURL, err := base64.URLEncoding.DecodeString(encodedURL)
|
||||
if err != nil {
|
||||
html.BadRequest(w, r, errors.New("Unable to decode this URL"))
|
||||
html.BadRequest(w, r, errors.New("unable to decode this URL"))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,9 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
mediaURL := string(decodedURL)
|
||||
logger.Debug(`[Proxy] Fetching %q`, mediaURL)
|
||||
slog.Debug("MediaProxy: Fetching remote resource",
|
||||
slog.String("media_url", mediaURL),
|
||||
)
|
||||
|
||||
req, err := http.NewRequest("GET", mediaURL, nil)
|
||||
if err != nil {
|
||||
|
@ -82,19 +84,28 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
resp, err := clt.Do(req)
|
||||
if err != nil {
|
||||
logger.Error(`[Proxy] Unable to initialize HTTP client: %v`, err)
|
||||
slog.Error("MediaProxy: Unable to initialize HTTP client",
|
||||
slog.String("media_url", mediaURL),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusRequestedRangeNotSatisfiable {
|
||||
logger.Error(`[Proxy] Status Code is %d for URL %q`, resp.StatusCode, mediaURL)
|
||||
slog.Warn("MediaProxy: "+http.StatusText(http.StatusRequestedRangeNotSatisfiable),
|
||||
slog.String("media_url", mediaURL),
|
||||
slog.Int("status_code", resp.StatusCode),
|
||||
)
|
||||
html.RequestedRangeNotSatisfiable(w, r, resp.Header.Get("Content-Range"))
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
|
||||
logger.Error(`[Proxy] Status Code is %d for URL %q`, resp.StatusCode, mediaURL)
|
||||
slog.Warn("MediaProxy: Unexpected response status code",
|
||||
slog.String("media_url", mediaURL),
|
||||
slog.Int("status_code", resp.StatusCode),
|
||||
)
|
||||
html.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -9,14 +9,14 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
)
|
||||
|
||||
func (h *handler) removeSession(w http.ResponseWriter, r *http.Request) {
|
||||
sessionID := request.RouteInt64Param(r, "sessionID")
|
||||
err := h.store.RemoveUserSessionByID(request.UserID(r), sessionID)
|
||||
if err != nil {
|
||||
logger.Error("[UI:RemoveSession] %v", err)
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
html.Redirect(w, r, route.Path(h.router, "sessions"))
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/locale"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
"miniflux.app/v2/internal/ui/form"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
|
@ -74,9 +73,7 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
err = h.store.UpdateUser(settingsForm.Merge(loggedUser))
|
||||
if err != nil {
|
||||
logger.Error("[UI:UpdateSettings] %v", err)
|
||||
view.Set("errorMessage", "error.unable_to_update_user")
|
||||
html.OK(w, r, view.Render("settings"))
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
feedHandler "miniflux.app/v2/internal/reader/handler"
|
||||
"miniflux.app/v2/internal/reader/subscription"
|
||||
|
@ -61,15 +60,12 @@ func (h *handler) submitSubscription(w http.ResponseWriter, r *http.Request) {
|
|||
subscriptionForm.AllowSelfSignedCertificates,
|
||||
)
|
||||
if findErr != nil {
|
||||
logger.Error("[UI:SubmitSubscription] %q -> %s", subscriptionForm.URL, findErr)
|
||||
v.Set("form", subscriptionForm)
|
||||
v.Set("errorMessage", findErr)
|
||||
html.OK(w, r, v.Render("add_subscription"))
|
||||
return
|
||||
}
|
||||
|
||||
logger.Debug("[UI:SubmitSubscription] %s", subscriptions)
|
||||
|
||||
n := len(subscriptions)
|
||||
switch {
|
||||
case n == 0:
|
||||
|
|
|
@ -6,7 +6,6 @@ package ui // import "miniflux.app/v2/internal/ui"
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/storage"
|
||||
"miniflux.app/v2/internal/template"
|
||||
"miniflux.app/v2/internal/worker"
|
||||
|
@ -20,7 +19,7 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) {
|
|||
|
||||
templateEngine := template.NewEngine(router)
|
||||
if err := templateEngine.ParseTemplates(); err != nil {
|
||||
logger.Fatal(`Unable to parse templates: %v`, err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
handler := &handler{router, store, templateEngine, pool}
|
||||
|
|
|
@ -37,7 +37,7 @@ func (h *handler) removeUser(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if selectedUser.ID == loggedUser.ID {
|
||||
html.BadRequest(w, r, errors.New("You cannot remove yourself"))
|
||||
html.BadRequest(w, r, errors.New("you cannot remove yourself"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/model"
|
||||
"miniflux.app/v2/internal/ui/form"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
|
@ -64,9 +63,7 @@ func (h *handler) saveUser(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if _, err := h.store.CreateUser(userCreationRequest); err != nil {
|
||||
logger.Error("[UI:SaveUser] %v", err)
|
||||
view.Set("errorMessage", "error.unable_to_create_user")
|
||||
html.OK(w, r, view.Render("create_user"))
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"miniflux.app/v2/internal/http/request"
|
||||
"miniflux.app/v2/internal/http/response/html"
|
||||
"miniflux.app/v2/internal/http/route"
|
||||
"miniflux.app/v2/internal/logger"
|
||||
"miniflux.app/v2/internal/ui/form"
|
||||
"miniflux.app/v2/internal/ui/session"
|
||||
"miniflux.app/v2/internal/ui/view"
|
||||
|
@ -64,9 +63,7 @@ func (h *handler) updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
userForm.Merge(selectedUser)
|
||||
if err := h.store.UpdateUser(selectedUser); err != nil {
|
||||
logger.Error("[UI:UpdateUser] %v", err)
|
||||
view.Set("errorMessage", "error.unable_to_update_user")
|
||||
html.OK(w, r, view.Render("edit_user"))
|
||||
html.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue