1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-08-16 18:01:37 +00:00

refactor(ui): standardize user variable naming and avoid a SQL query when only userID is used

- Use `user` everywhere, instead of sometimes `loggedUser`
- Delay the instantiation of some variables: no need to perform SQL queries for
  nothing.
- Remove a SQL query getting the whole user struct when only user.ID is used.
This commit is contained in:
Julien Voisin 2025-08-12 04:48:36 +02:00 committed by GitHub
parent 50c5996280
commit 5d9d0b2652
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 50 additions and 57 deletions

View file

@ -17,7 +17,7 @@ import (
) )
func (h *handler) saveAPIKey(w http.ResponseWriter, r *http.Request) { func (h *handler) saveAPIKey(w http.ResponseWriter, r *http.Request) {
loggedUser, err := h.store.UserByID(request.UserID(r)) user, err := h.store.UserByID(request.UserID(r))
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
@ -28,20 +28,20 @@ func (h *handler) saveAPIKey(w http.ResponseWriter, r *http.Request) {
Description: apiKeyForm.Description, Description: apiKeyForm.Description,
} }
if validationErr := validator.ValidateAPIKeyCreation(h.store, loggedUser.ID, apiKeyCreationRequest); validationErr != nil { if validationErr := validator.ValidateAPIKeyCreation(h.store, user.ID, apiKeyCreationRequest); validationErr != nil {
sess := session.New(h.store, request.SessionID(r)) sess := session.New(h.store, request.SessionID(r))
view := view.New(h.tpl, r, sess) view := view.New(h.tpl, r, sess)
view.Set("form", apiKeyForm) view.Set("form", apiKeyForm)
view.Set("menu", "settings") view.Set("menu", "settings")
view.Set("user", loggedUser) view.Set("user", user)
view.Set("countUnread", h.store.CountUnreadEntries(loggedUser.ID)) view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(loggedUser.ID)) view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID))
view.Set("errorMessage", validationErr.Translate(loggedUser.Language)) view.Set("errorMessage", validationErr.Translate(user.Language))
html.OK(w, r, view.Render("create_api_key")) html.OK(w, r, view.Render("create_api_key"))
return return
} }
if _, err = h.store.CreateAPIKey(loggedUser.ID, apiKeyCreationRequest.Description); err != nil { if _, err = h.store.CreateAPIKey(user.ID, apiKeyCreationRequest.Description); err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
} }

View file

@ -27,7 +27,6 @@ func (h *handler) refreshCategoryFeedsPage(w http.ResponseWriter, r *http.Reques
} }
func (h *handler) refreshCategory(w http.ResponseWriter, r *http.Request) int64 { func (h *handler) refreshCategory(w http.ResponseWriter, r *http.Request) int64 {
userID := request.UserID(r)
categoryID := request.RouteInt64Param(r, "categoryID") categoryID := request.RouteInt64Param(r, "categoryID")
printer := locale.NewPrinter(request.UserLanguage(r)) printer := locale.NewPrinter(request.UserLanguage(r))
sess := session.New(h.store, request.SessionID(r)) sess := session.New(h.store, request.SessionID(r))
@ -37,6 +36,7 @@ func (h *handler) refreshCategory(w http.ResponseWriter, r *http.Request) int64
time := config.Opts.ForceRefreshInterval() time := config.Opts.ForceRefreshInterval()
sess.NewFlashErrorMessage(printer.Plural("alert.too_many_feeds_refresh", time, time)) sess.NewFlashErrorMessage(printer.Plural("alert.too_many_feeds_refresh", time, time))
} else { } else {
userID := request.UserID(r)
// We allow the end-user to force refresh all its feeds in this category // We allow the end-user to force refresh all its feeds in this category
// without taking into consideration the number of errors. // without taking into consideration the number of errors.
batchBuilder := h.store.NewBatchBuilder() batchBuilder := h.store.NewBatchBuilder()

View file

@ -17,7 +17,7 @@ import (
) )
func (h *handler) saveCategory(w http.ResponseWriter, r *http.Request) { func (h *handler) saveCategory(w http.ResponseWriter, r *http.Request) {
loggedUser, err := h.store.UserByID(request.UserID(r)) user, err := h.store.UserByID(request.UserID(r))
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
@ -29,19 +29,19 @@ func (h *handler) saveCategory(w http.ResponseWriter, r *http.Request) {
view := view.New(h.tpl, r, sess) view := view.New(h.tpl, r, sess)
view.Set("form", categoryForm) view.Set("form", categoryForm)
view.Set("menu", "categories") view.Set("menu", "categories")
view.Set("user", loggedUser) view.Set("user", user)
view.Set("countUnread", h.store.CountUnreadEntries(loggedUser.ID)) view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(loggedUser.ID)) view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID))
categoryCreationRequest := &model.CategoryCreationRequest{Title: categoryForm.Title} categoryCreationRequest := &model.CategoryCreationRequest{Title: categoryForm.Title}
if validationErr := validator.ValidateCategoryCreation(h.store, loggedUser.ID, categoryCreationRequest); validationErr != nil { if validationErr := validator.ValidateCategoryCreation(h.store, user.ID, categoryCreationRequest); validationErr != nil {
view.Set("errorMessage", validationErr.Translate(loggedUser.Language)) view.Set("errorMessage", validationErr.Translate(user.Language))
html.OK(w, r, view.Render("create_category")) html.OK(w, r, view.Render("create_category"))
return return
} }
if _, err = h.store.CreateCategory(loggedUser.ID, categoryCreationRequest); err != nil { if _, err = h.store.CreateCategory(user.ID, categoryCreationRequest); err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
} }

View file

@ -17,7 +17,7 @@ import (
) )
func (h *handler) updateCategory(w http.ResponseWriter, r *http.Request) { func (h *handler) updateCategory(w http.ResponseWriter, r *http.Request) {
loggedUser, err := h.store.UserByID(request.UserID(r)) user, err := h.store.UserByID(request.UserID(r))
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
@ -42,17 +42,17 @@ func (h *handler) updateCategory(w http.ResponseWriter, r *http.Request) {
view.Set("form", categoryForm) view.Set("form", categoryForm)
view.Set("category", category) view.Set("category", category)
view.Set("menu", "categories") view.Set("menu", "categories")
view.Set("user", loggedUser) view.Set("user", user)
view.Set("countUnread", h.store.CountUnreadEntries(loggedUser.ID)) view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(loggedUser.ID)) view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID))
categoryRequest := &model.CategoryModificationRequest{ categoryRequest := &model.CategoryModificationRequest{
Title: model.SetOptionalField(categoryForm.Title), Title: model.SetOptionalField(categoryForm.Title),
HideGlobally: model.SetOptionalField(categoryForm.HideGlobally), HideGlobally: model.SetOptionalField(categoryForm.HideGlobally),
} }
if validationErr := validator.ValidateCategoryModification(h.store, loggedUser.ID, category.ID, categoryRequest); validationErr != nil { if validationErr := validator.ValidateCategoryModification(h.store, user.ID, category.ID, categoryRequest); validationErr != nil {
view.Set("errorMessage", validationErr.Translate(loggedUser.Language)) view.Set("errorMessage", validationErr.Translate(user.Language))
html.OK(w, r, view.Render("create_category")) html.OK(w, r, view.Render("create_category"))
return return
} }

View file

@ -20,13 +20,9 @@ import (
func (h *handler) updateIntegration(w http.ResponseWriter, r *http.Request) { func (h *handler) updateIntegration(w http.ResponseWriter, r *http.Request) {
printer := locale.NewPrinter(request.UserLanguage(r)) printer := locale.NewPrinter(request.UserLanguage(r))
sess := session.New(h.store, request.SessionID(r)) sess := session.New(h.store, request.SessionID(r))
user, err := h.store.UserByID(request.UserID(r)) userID := request.UserID(r)
if err != nil {
html.ServerError(w, r, err)
return
}
integration, err := h.store.Integration(user.ID) integration, err := h.store.Integration(userID)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
@ -35,7 +31,7 @@ func (h *handler) updateIntegration(w http.ResponseWriter, r *http.Request) {
integrationForm := form.NewIntegrationForm(r) integrationForm := form.NewIntegrationForm(r)
integrationForm.Merge(integration) integrationForm.Merge(integration)
if integration.FeverUsername != "" && h.store.HasDuplicateFeverUsername(user.ID, integration.FeverUsername) { if integration.FeverUsername != "" && h.store.HasDuplicateFeverUsername(userID, integration.FeverUsername) {
sess.NewFlashErrorMessage(printer.Print("error.duplicate_fever_username")) sess.NewFlashErrorMessage(printer.Print("error.duplicate_fever_username"))
html.Redirect(w, r, route.Path(h.router, "integrations")) html.Redirect(w, r, route.Path(h.router, "integrations"))
return return
@ -49,7 +45,7 @@ func (h *handler) updateIntegration(w http.ResponseWriter, r *http.Request) {
integration.FeverToken = "" integration.FeverToken = ""
} }
if integration.GoogleReaderUsername != "" && h.store.HasDuplicateGoogleReaderUsername(user.ID, integration.GoogleReaderUsername) { if integration.GoogleReaderUsername != "" && h.store.HasDuplicateGoogleReaderUsername(userID, integration.GoogleReaderUsername) {
sess.NewFlashErrorMessage(printer.Print("error.duplicate_googlereader_username")) sess.NewFlashErrorMessage(printer.Print("error.duplicate_googlereader_username"))
html.Redirect(w, r, route.Path(h.router, "integrations")) html.Redirect(w, r, route.Path(h.router, "integrations"))
return return

View file

@ -20,10 +20,6 @@ import (
) )
func (h *handler) oauth2Callback(w http.ResponseWriter, r *http.Request) { func (h *handler) oauth2Callback(w http.ResponseWriter, r *http.Request) {
clientIP := request.ClientIP(r)
printer := locale.NewPrinter(request.UserLanguage(r))
sess := session.New(h.store, request.SessionID(r))
provider := request.RouteStringParam(r, "provider") provider := request.RouteStringParam(r, "provider")
if provider == "" { if provider == "" {
slog.Warn("Invalid or missing OAuth2 provider") slog.Warn("Invalid or missing OAuth2 provider")
@ -68,6 +64,9 @@ func (h *handler) oauth2Callback(w http.ResponseWriter, r *http.Request) {
return return
} }
printer := locale.NewPrinter(request.UserLanguage(r))
sess := session.New(h.store, request.SessionID(r))
if request.IsAuthenticated(r) { if request.IsAuthenticated(r) {
loggedUser, err := h.store.UserByID(request.UserID(r)) loggedUser, err := h.store.UserByID(request.UserID(r))
if err != nil { if err != nil {
@ -124,6 +123,7 @@ func (h *handler) oauth2Callback(w http.ResponseWriter, r *http.Request) {
} }
} }
clientIP := request.ClientIP(r)
sessionToken, _, err := h.store.CreateUserSessionFromUsername(user.Username, r.UserAgent(), clientIP) sessionToken, _, err := h.store.CreateUserSessionFromUsername(user.Username, r.UserAgent(), clientIP)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)

View file

@ -15,8 +15,6 @@ import (
) )
func (h *handler) oauth2Redirect(w http.ResponseWriter, r *http.Request) { func (h *handler) oauth2Redirect(w http.ResponseWriter, r *http.Request) {
sess := session.New(h.store, request.SessionID(r))
provider := request.RouteStringParam(r, "provider") provider := request.RouteStringParam(r, "provider")
if provider == "" { if provider == "" {
slog.Warn("Invalid or missing OAuth2 provider") slog.Warn("Invalid or missing OAuth2 provider")
@ -36,6 +34,7 @@ func (h *handler) oauth2Redirect(w http.ResponseWriter, r *http.Request) {
auth := oauth2.GenerateAuthorization(authProvider.GetConfig()) auth := oauth2.GenerateAuthorization(authProvider.GetConfig())
sess := session.New(h.store, request.SessionID(r))
sess.SetOAuth2State(auth.State()) sess.SetOAuth2State(auth.State())
sess.SetOAuth2CodeVerifier(auth.CodeVerifier()) sess.SetOAuth2CodeVerifier(auth.CodeVerifier())

View file

@ -24,7 +24,6 @@ func (h *handler) oauth2Unlink(w http.ResponseWriter, r *http.Request) {
return return
} }
printer := locale.NewPrinter(request.UserLanguage(r))
provider := request.RouteStringParam(r, "provider") provider := request.RouteStringParam(r, "provider")
if provider == "" { if provider == "" {
slog.Warn("Invalid or missing OAuth2 provider") slog.Warn("Invalid or missing OAuth2 provider")
@ -42,7 +41,6 @@ func (h *handler) oauth2Unlink(w http.ResponseWriter, r *http.Request) {
return return
} }
sess := session.New(h.store, request.SessionID(r))
user, err := h.store.UserByID(request.UserID(r)) user, err := h.store.UserByID(request.UserID(r))
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
@ -55,6 +53,8 @@ func (h *handler) oauth2Unlink(w http.ResponseWriter, r *http.Request) {
return return
} }
sess := session.New(h.store, request.SessionID(r))
printer := locale.NewPrinter(request.UserLanguage(r))
if !hasPassword { if !hasPassword {
sess.NewFlashErrorMessage(printer.Print("error.unlink_account_without_password")) sess.NewFlashErrorMessage(printer.Print("error.unlink_account_without_password"))
html.Redirect(w, r, route.Path(h.router, "settings")) html.Redirect(w, r, route.Path(h.router, "settings"))

View file

@ -21,8 +21,7 @@ import (
) )
func (h *handler) uploadOPML(w http.ResponseWriter, r *http.Request) { func (h *handler) uploadOPML(w http.ResponseWriter, r *http.Request) {
loggedUserID := request.UserID(r) user, err := h.store.UserByID(request.UserID(r))
user, err := h.store.UserByID(loggedUserID)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
@ -31,7 +30,7 @@ func (h *handler) uploadOPML(w http.ResponseWriter, r *http.Request) {
file, fileHeader, err := r.FormFile("file") file, fileHeader, err := r.FormFile("file")
if err != nil { if err != nil {
slog.Error("OPML file upload error", slog.Error("OPML file upload error",
slog.Int64("user_id", loggedUserID), slog.Int64("user_id", user.ID),
slog.Any("error", err), slog.Any("error", err),
) )
@ -41,7 +40,7 @@ func (h *handler) uploadOPML(w http.ResponseWriter, r *http.Request) {
defer file.Close() defer file.Close()
slog.Info("OPML file uploaded", slog.Info("OPML file uploaded",
slog.Int64("user_id", loggedUserID), slog.Int64("user_id", user.ID),
slog.String("file_name", fileHeader.Filename), slog.String("file_name", fileHeader.Filename),
slog.Int64("file_size", fileHeader.Size), slog.Int64("file_size", fileHeader.Size),
) )
@ -69,8 +68,7 @@ func (h *handler) uploadOPML(w http.ResponseWriter, r *http.Request) {
} }
func (h *handler) fetchOPML(w http.ResponseWriter, r *http.Request) { func (h *handler) fetchOPML(w http.ResponseWriter, r *http.Request) {
loggedUserID := request.UserID(r) user, err := h.store.UserByID(request.UserID(r))
user, err := h.store.UserByID(loggedUserID)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
@ -83,7 +81,7 @@ func (h *handler) fetchOPML(w http.ResponseWriter, r *http.Request) {
} }
slog.Info("Fetching OPML file remotely", slog.Info("Fetching OPML file remotely",
slog.Int64("user_id", loggedUserID), slog.Int64("user_id", user.ID),
slog.String("opml_file_url", opmlFileURL), slog.String("opml_file_url", opmlFileURL),
) )

View file

@ -30,13 +30,13 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) {
return return
} }
encodedDigest := request.RouteStringParam(r, "encodedDigest")
encodedURL := request.RouteStringParam(r, "encodedURL") encodedURL := request.RouteStringParam(r, "encodedURL")
if encodedURL == "" { if encodedURL == "" {
html.BadRequest(w, r, errors.New("no URL provided")) html.BadRequest(w, r, errors.New("no URL provided"))
return return
} }
encodedDigest := request.RouteStringParam(r, "encodedDigest")
decodedDigest, err := base64.URLEncoding.DecodeString(encodedDigest) decodedDigest, err := base64.URLEncoding.DecodeString(encodedDigest)
if err != nil { 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"))

View file

@ -18,7 +18,7 @@ import (
) )
func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) { func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
loggedUser, err := h.store.UserByID(request.UserID(r)) user, err := h.store.UserByID(request.UserID(r))
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
@ -30,7 +30,7 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
return return
} }
creds, err := h.store.WebAuthnCredentialsByUserID(loggedUser.ID) creds, err := h.store.WebAuthnCredentialsByUserID(user.ID)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
@ -51,16 +51,16 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
view.Set("languages", locale.AvailableLanguages) view.Set("languages", locale.AvailableLanguages)
view.Set("timezones", timezones) view.Set("timezones", timezones)
view.Set("menu", "settings") view.Set("menu", "settings")
view.Set("user", loggedUser) view.Set("user", user)
view.Set("countUnread", h.store.CountUnreadEntries(loggedUser.ID)) view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(loggedUser.ID)) view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID))
view.Set("default_home_pages", model.HomePages()) view.Set("default_home_pages", model.HomePages())
view.Set("categories_sorting_options", model.CategoriesSortingOptions()) view.Set("categories_sorting_options", model.CategoriesSortingOptions())
view.Set("countWebAuthnCerts", h.store.CountWebAuthnCredentialsByUserID(loggedUser.ID)) view.Set("countWebAuthnCerts", h.store.CountWebAuthnCredentialsByUserID(user.ID))
view.Set("webAuthnCerts", creds) view.Set("webAuthnCerts", creds)
if validationErr := settingsForm.Validate(); validationErr != nil { if validationErr := settingsForm.Validate(); validationErr != nil {
view.Set("errorMessage", validationErr.Translate(loggedUser.Language)) view.Set("errorMessage", validationErr.Translate(user.Language))
html.OK(w, r, view.Render("settings")) html.OK(w, r, view.Render("settings"))
return return
} }
@ -86,20 +86,20 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
ExternalFontHosts: model.OptionalString(settingsForm.ExternalFontHosts), ExternalFontHosts: model.OptionalString(settingsForm.ExternalFontHosts),
} }
if validationErr := validator.ValidateUserModification(h.store, loggedUser.ID, userModificationRequest); validationErr != nil { if validationErr := validator.ValidateUserModification(h.store, user.ID, userModificationRequest); validationErr != nil {
view.Set("errorMessage", validationErr.Translate(loggedUser.Language)) view.Set("errorMessage", validationErr.Translate(user.Language))
html.OK(w, r, view.Render("settings")) html.OK(w, r, view.Render("settings"))
return return
} }
err = h.store.UpdateUser(settingsForm.Merge(loggedUser)) err = h.store.UpdateUser(settingsForm.Merge(user))
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)
return return
} }
sess.SetLanguage(loggedUser.Language) sess.SetLanguage(user.Language)
sess.SetTheme(loggedUser.Theme) sess.SetTheme(user.Theme)
sess.NewFlashMessage(locale.NewPrinter(request.UserLanguage(r)).Printf("alert.prefs_saved")) sess.NewFlashMessage(locale.NewPrinter(request.UserLanguage(r)).Printf("alert.prefs_saved"))
html.Redirect(w, r, route.Path(h.router, "settings")) html.Redirect(w, r, route.Path(h.router, "settings"))
} }