aboutsummaryrefslogtreecommitdiffhomepage
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/category_edit.go7
-rw-r--r--ui/category_entries.go7
-rw-r--r--ui/category_remove.go7
-rw-r--r--ui/category_update.go7
-rw-r--r--ui/entry_bookmark.go7
-rw-r--r--ui/entry_category.go13
-rw-r--r--ui/entry_feed.go13
-rw-r--r--ui/entry_read.go7
-rw-r--r--ui/entry_save.go7
-rw-r--r--ui/entry_scraper.go7
-rw-r--r--ui/entry_search.go9
-rw-r--r--ui/entry_toggle_bookmark.go7
-rw-r--r--ui/entry_unread.go7
-rw-r--r--ui/feed_edit.go7
-rw-r--r--ui/feed_entries.go7
-rw-r--r--ui/feed_icon.go7
-rw-r--r--ui/feed_refresh.go7
-rw-r--r--ui/feed_remove.go9
-rw-r--r--ui/feed_update.go7
-rw-r--r--ui/oauth2_callback.go6
-rw-r--r--ui/oauth2_redirect.go2
-rw-r--r--ui/oauth2_unlink.go2
-rw-r--r--ui/proxy.go2
-rw-r--r--ui/search_entries.go2
-rw-r--r--ui/session_remove.go12
-rw-r--r--ui/static_app_icon.go4
-rw-r--r--ui/static_javascript.go4
-rw-r--r--ui/static_stylesheet.go4
-rw-r--r--ui/subscription_bookmarklet.go2
-rw-r--r--ui/user_edit.go7
-rw-r--r--ui/user_remove.go9
-rw-r--r--ui/user_update.go7
32 files changed, 44 insertions, 168 deletions
diff --git a/ui/category_edit.go b/ui/category_edit.go
index 0ab4b1b..b99d2a0 100644
--- a/ui/category_edit.go
+++ b/ui/category_edit.go
@@ -25,12 +25,7 @@ func (c *Controller) EditCategory(w http.ResponseWriter, r *http.Request) {
return
}
- categoryID, err := request.IntParam(r, "categoryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ categoryID := request.RouteInt64Param(r, "categoryID")
category, err := c.store.Category(request.UserID(r), categoryID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/category_entries.go b/ui/category_entries.go
index ac39fa1..caa98cd 100644
--- a/ui/category_entries.go
+++ b/ui/category_entries.go
@@ -23,12 +23,7 @@ func (c *Controller) CategoryEntries(w http.ResponseWriter, r *http.Request) {
return
}
- categoryID, err := request.IntParam(r, "categoryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ categoryID := request.RouteInt64Param(r, "categoryID")
category, err := c.store.Category(request.UserID(r), categoryID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/category_remove.go b/ui/category_remove.go
index 033d9e3..b424af5 100644
--- a/ui/category_remove.go
+++ b/ui/category_remove.go
@@ -21,12 +21,7 @@ func (c *Controller) RemoveCategory(w http.ResponseWriter, r *http.Request) {
return
}
- categoryID, err := request.IntParam(r, "categoryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ categoryID := request.RouteInt64Param(r, "categoryID")
category, err := c.store.Category(request.UserID(r), categoryID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/category_update.go b/ui/category_update.go
index 480b4fb..90672c0 100644
--- a/ui/category_update.go
+++ b/ui/category_update.go
@@ -25,12 +25,7 @@ func (c *Controller) UpdateCategory(w http.ResponseWriter, r *http.Request) {
return
}
- categoryID, err := request.IntParam(r, "categoryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ categoryID := request.RouteInt64Param(r, "categoryID")
category, err := c.store.Category(request.UserID(r), categoryID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/entry_bookmark.go b/ui/entry_bookmark.go
index e6d2f0e..7c42a5c 100644
--- a/ui/entry_bookmark.go
+++ b/ui/entry_bookmark.go
@@ -25,12 +25,7 @@ func (c *Controller) ShowStarredEntry(w http.ResponseWriter, r *http.Request) {
return
}
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ entryID := request.RouteInt64Param(r, "entryID")
builder := c.store.NewEntryQueryBuilder(user.ID)
builder.WithEntryID(entryID)
builder.WithoutStatus(model.EntryStatusRemoved)
diff --git a/ui/entry_category.go b/ui/entry_category.go
index 795aaf1..283f015 100644
--- a/ui/entry_category.go
+++ b/ui/entry_category.go
@@ -25,17 +25,8 @@ func (c *Controller) ShowCategoryEntry(w http.ResponseWriter, r *http.Request) {
return
}
- categoryID, err := request.IntParam(r, "categoryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
+ categoryID := request.RouteInt64Param(r, "categoryID")
+ entryID := request.RouteInt64Param(r, "entryID")
builder := c.store.NewEntryQueryBuilder(user.ID)
builder.WithCategoryID(categoryID)
diff --git a/ui/entry_feed.go b/ui/entry_feed.go
index 968c8f4..86dd2c9 100644
--- a/ui/entry_feed.go
+++ b/ui/entry_feed.go
@@ -25,17 +25,8 @@ func (c *Controller) ShowFeedEntry(w http.ResponseWriter, r *http.Request) {
return
}
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
- feedID, err := request.IntParam(r, "feedID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
+ entryID := request.RouteInt64Param(r, "entryID")
+ feedID := request.RouteInt64Param(r, "feedID")
builder := c.store.NewEntryQueryBuilder(user.ID)
builder.WithFeedID(feedID)
diff --git a/ui/entry_read.go b/ui/entry_read.go
index 61c7114..eeaca8e 100644
--- a/ui/entry_read.go
+++ b/ui/entry_read.go
@@ -24,12 +24,7 @@ func (c *Controller) ShowReadEntry(w http.ResponseWriter, r *http.Request) {
return
}
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ entryID := request.RouteInt64Param(r, "entryID")
builder := c.store.NewEntryQueryBuilder(user.ID)
builder.WithEntryID(entryID)
builder.WithoutStatus(model.EntryStatusRemoved)
diff --git a/ui/entry_save.go b/ui/entry_save.go
index 488022a..1f846ba 100644
--- a/ui/entry_save.go
+++ b/ui/entry_save.go
@@ -16,12 +16,7 @@ import (
// SaveEntry send the link to external services.
func (c *Controller) SaveEntry(w http.ResponseWriter, r *http.Request) {
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- json.BadRequest(w, err)
- return
- }
-
+ entryID := request.RouteInt64Param(r, "entryID")
builder := c.store.NewEntryQueryBuilder(request.UserID(r))
builder.WithEntryID(entryID)
builder.WithoutStatus(model.EntryStatusRemoved)
diff --git a/ui/entry_scraper.go b/ui/entry_scraper.go
index b4a290f..4c2d58c 100644
--- a/ui/entry_scraper.go
+++ b/ui/entry_scraper.go
@@ -17,12 +17,7 @@ import (
// FetchContent downloads the original HTML page and returns relevant contents.
func (c *Controller) FetchContent(w http.ResponseWriter, r *http.Request) {
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- json.BadRequest(w, err)
- return
- }
-
+ entryID := request.RouteInt64Param(r, "entryID")
builder := c.store.NewEntryQueryBuilder(request.UserID(r))
builder.WithEntryID(entryID)
builder.WithoutStatus(model.EntryStatusRemoved)
diff --git a/ui/entry_search.go b/ui/entry_search.go
index 15babc1..8acf103 100644
--- a/ui/entry_search.go
+++ b/ui/entry_search.go
@@ -25,13 +25,8 @@ func (c *Controller) ShowSearchEntry(w http.ResponseWriter, r *http.Request) {
return
}
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
- searchQuery := request.QueryParam(r, "q", "")
+ entryID := request.RouteInt64Param(r, "entryID")
+ searchQuery := request.QueryStringParam(r, "q", "")
builder := c.store.NewEntryQueryBuilder(user.ID)
builder.WithSearchQuery(searchQuery)
builder.WithEntryID(entryID)
diff --git a/ui/entry_toggle_bookmark.go b/ui/entry_toggle_bookmark.go
index e8e87ca..14a2c75 100644
--- a/ui/entry_toggle_bookmark.go
+++ b/ui/entry_toggle_bookmark.go
@@ -14,12 +14,7 @@ import (
// ToggleBookmark handles Ajax request to toggle bookmark value.
func (c *Controller) ToggleBookmark(w http.ResponseWriter, r *http.Request) {
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- json.BadRequest(w, err)
- return
- }
-
+ entryID := request.RouteInt64Param(r, "entryID")
if err := c.store.ToggleBookmark(request.UserID(r), entryID); err != nil {
logger.Error("[Controller:ToggleBookmark] %v", err)
json.ServerError(w, nil)
diff --git a/ui/entry_unread.go b/ui/entry_unread.go
index 30a6d34..4ef5731 100644
--- a/ui/entry_unread.go
+++ b/ui/entry_unread.go
@@ -25,12 +25,7 @@ func (c *Controller) ShowUnreadEntry(w http.ResponseWriter, r *http.Request) {
return
}
- entryID, err := request.IntParam(r, "entryID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ entryID := request.RouteInt64Param(r, "entryID")
builder := c.store.NewEntryQueryBuilder(user.ID)
builder.WithEntryID(entryID)
builder.WithoutStatus(model.EntryStatusRemoved)
diff --git a/ui/feed_edit.go b/ui/feed_edit.go
index 9063d51..8b1b3cb 100644
--- a/ui/feed_edit.go
+++ b/ui/feed_edit.go
@@ -23,12 +23,7 @@ func (c *Controller) EditFeed(w http.ResponseWriter, r *http.Request) {
return
}
- feedID, err := request.IntParam(r, "feedID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ feedID := request.RouteInt64Param(r, "feedID")
feed, err := c.store.FeedByID(user.ID, feedID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/feed_entries.go b/ui/feed_entries.go
index dc0f05d..06a298b 100644
--- a/ui/feed_entries.go
+++ b/ui/feed_entries.go
@@ -23,12 +23,7 @@ func (c *Controller) ShowFeedEntries(w http.ResponseWriter, r *http.Request) {
return
}
- feedID, err := request.IntParam(r, "feedID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ feedID := request.RouteInt64Param(r, "feedID")
feed, err := c.store.FeedByID(user.ID, feedID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/feed_icon.go b/ui/feed_icon.go
index c5a7414..0aa7089 100644
--- a/ui/feed_icon.go
+++ b/ui/feed_icon.go
@@ -15,12 +15,7 @@ import (
// ShowIcon shows the feed icon.
func (c *Controller) ShowIcon(w http.ResponseWriter, r *http.Request) {
- iconID, err := request.IntParam(r, "iconID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ iconID := request.RouteInt64Param(r, "iconID")
icon, err := c.store.IconByID(iconID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/feed_refresh.go b/ui/feed_refresh.go
index d9da238..df93c6e 100644
--- a/ui/feed_refresh.go
+++ b/ui/feed_refresh.go
@@ -16,12 +16,7 @@ import (
// RefreshFeed refresh a subscription and redirect to the feed entries page.
func (c *Controller) RefreshFeed(w http.ResponseWriter, r *http.Request) {
- feedID, err := request.IntParam(r, "feedID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ feedID := request.RouteInt64Param(r, "feedID")
if err := c.feedHandler.RefreshFeed(request.UserID(r), feedID); err != nil {
logger.Error("[Controller:RefreshFeed] %v", err)
}
diff --git a/ui/feed_remove.go b/ui/feed_remove.go
index 9071a33..d1ab01a 100644
--- a/ui/feed_remove.go
+++ b/ui/feed_remove.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
-package ui // import "miniflux.app/ui"
+package ui // import "miniflux.app/ui"
import (
"net/http"
@@ -15,12 +15,7 @@ import (
// RemoveFeed deletes a subscription from the database and redirect to the list of feeds page.
func (c *Controller) RemoveFeed(w http.ResponseWriter, r *http.Request) {
- feedID, err := request.IntParam(r, "feedID")
- if err != nil {
- html.ServerError(w, err)
- return
- }
-
+ feedID := request.RouteInt64Param(r, "feedID")
if err := c.store.RemoveFeed(request.UserID(r), feedID); err != nil {
html.ServerError(w, err)
return
diff --git a/ui/feed_update.go b/ui/feed_update.go
index a6fbcbf..6cc4776 100644
--- a/ui/feed_update.go
+++ b/ui/feed_update.go
@@ -26,12 +26,7 @@ func (c *Controller) UpdateFeed(w http.ResponseWriter, r *http.Request) {
return
}
- feedID, err := request.IntParam(r, "feedID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ feedID := request.RouteInt64Param(r, "feedID")
feed, err := c.store.FeedByID(user.ID, feedID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/oauth2_callback.go b/ui/oauth2_callback.go
index 9f51d0a..1902d6e 100644
--- a/ui/oauth2_callback.go
+++ b/ui/oauth2_callback.go
@@ -23,21 +23,21 @@ func (c *Controller) OAuth2Callback(w http.ResponseWriter, r *http.Request) {
printer := locale.NewPrinter(request.UserLanguage(r))
sess := session.New(c.store, request.SessionID(r))
- provider := request.Param(r, "provider", "")
+ provider := request.RouteStringParam(r, "provider")
if provider == "" {
logger.Error("[OAuth2] Invalid or missing provider")
response.Redirect(w, r, route.Path(c.router, "login"))
return
}
- code := request.QueryParam(r, "code", "")
+ code := request.QueryStringParam(r, "code", "")
if code == "" {
logger.Error("[OAuth2] No code received on callback")
response.Redirect(w, r, route.Path(c.router, "login"))
return
}
- state := request.QueryParam(r, "state", "")
+ state := request.QueryStringParam(r, "state", "")
if state == "" || state != request.OAuth2State(r) {
logger.Error(`[OAuth2] Invalid state value: got "%s" instead of "%s"`, state, request.OAuth2State(r))
response.Redirect(w, r, route.Path(c.router, "login"))
diff --git a/ui/oauth2_redirect.go b/ui/oauth2_redirect.go
index 3b7c88a..90c20b1 100644
--- a/ui/oauth2_redirect.go
+++ b/ui/oauth2_redirect.go
@@ -18,7 +18,7 @@ import (
func (c *Controller) OAuth2Redirect(w http.ResponseWriter, r *http.Request) {
sess := session.New(c.store, request.SessionID(r))
- provider := request.Param(r, "provider", "")
+ provider := request.RouteStringParam(r, "provider")
if provider == "" {
logger.Error("[OAuth2] Invalid or missing provider: %s", provider)
response.Redirect(w, r, route.Path(c.router, "login"))
diff --git a/ui/oauth2_unlink.go b/ui/oauth2_unlink.go
index 4435733..022e282 100644
--- a/ui/oauth2_unlink.go
+++ b/ui/oauth2_unlink.go
@@ -19,7 +19,7 @@ import (
// OAuth2Unlink unlink an account from the external provider.
func (c *Controller) OAuth2Unlink(w http.ResponseWriter, r *http.Request) {
printer := locale.NewPrinter(request.UserLanguage(r))
- provider := request.Param(r, "provider", "")
+ provider := request.RouteStringParam(r, "provider")
if provider == "" {
logger.Info("[OAuth2] Invalid or missing provider")
response.Redirect(w, r, route.Path(c.router, "login"))
diff --git a/ui/proxy.go b/ui/proxy.go
index 68e4db0..553dcce 100644
--- a/ui/proxy.go
+++ b/ui/proxy.go
@@ -27,7 +27,7 @@ func (c *Controller) ImageProxy(w http.ResponseWriter, r *http.Request) {
return
}
- encodedURL := request.Param(r, "encodedURL", "")
+ encodedURL := request.RouteStringParam(r, "encodedURL")
if encodedURL == "" {
html.BadRequest(w, errors.New("No URL provided"))
return
diff --git a/ui/search_entries.go b/ui/search_entries.go
index 3f17ede..e1dcbad 100644
--- a/ui/search_entries.go
+++ b/ui/search_entries.go
@@ -23,7 +23,7 @@ func (c *Controller) ShowSearchEntries(w http.ResponseWriter, r *http.Request) {
return
}
- searchQuery := request.QueryParam(r, "q", "")
+ searchQuery := request.QueryStringParam(r, "q", "")
offset := request.QueryIntParam(r, "offset", 0)
builder := c.store.NewEntryQueryBuilder(user.ID)
builder.WithSearchQuery(searchQuery)
diff --git a/ui/session_remove.go b/ui/session_remove.go
index f08cd3d..27201fd 100644
--- a/ui/session_remove.go
+++ b/ui/session_remove.go
@@ -2,27 +2,21 @@
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
-package ui // import "miniflux.app/ui"
+package ui // import "miniflux.app/ui"
import (
"net/http"
"miniflux.app/http/request"
"miniflux.app/http/response"
- "miniflux.app/http/response/html"
"miniflux.app/http/route"
"miniflux.app/logger"
)
// RemoveSession remove a user session.
func (c *Controller) RemoveSession(w http.ResponseWriter, r *http.Request) {
- sessionID, err := request.IntParam(r, "sessionID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
- err = c.store.RemoveUserSessionByID(request.UserID(r), sessionID)
+ sessionID := request.RouteInt64Param(r, "sessionID")
+ err := c.store.RemoveUserSessionByID(request.UserID(r), sessionID)
if err != nil {
logger.Error("[Controller:RemoveSession] %v", err)
}
diff --git a/ui/static_app_icon.go b/ui/static_app_icon.go
index 6da3f1a..2ad42fd 100644
--- a/ui/static_app_icon.go
+++ b/ui/static_app_icon.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
-package ui // import "miniflux.app/ui"
+package ui // import "miniflux.app/ui"
import (
"encoding/base64"
@@ -18,7 +18,7 @@ import (
// AppIcon renders application icons.
func (c *Controller) AppIcon(w http.ResponseWriter, r *http.Request) {
- filename := request.Param(r, "filename", "favicon.png")
+ filename := request.RouteStringParam(r, "filename")
encodedBlob, found := static.Binaries[filename]
if !found {
logger.Info("[Controller:AppIcon] This icon doesn't exists: %s", filename)
diff --git a/ui/static_javascript.go b/ui/static_javascript.go
index c52251c..248fae3 100644
--- a/ui/static_javascript.go
+++ b/ui/static_javascript.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
-package ui // import "miniflux.app/ui"
+package ui // import "miniflux.app/ui"
import (
"net/http"
@@ -16,7 +16,7 @@ import (
// Javascript renders application client side code.
func (c *Controller) Javascript(w http.ResponseWriter, r *http.Request) {
- filename := request.Param(r, "name", "app")
+ filename := request.RouteStringParam(r, "name")
if _, found := static.Javascripts[filename]; !found {
html.NotFound(w)
return
diff --git a/ui/static_stylesheet.go b/ui/static_stylesheet.go
index de540fe..8e475bd 100644
--- a/ui/static_stylesheet.go
+++ b/ui/static_stylesheet.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
-package ui // import "miniflux.app/ui"
+package ui // import "miniflux.app/ui"
import (
"net/http"
@@ -16,7 +16,7 @@ import (
// Stylesheet renders the CSS.
func (c *Controller) Stylesheet(w http.ResponseWriter, r *http.Request) {
- stylesheet := request.Param(r, "name", "default")
+ stylesheet := request.RouteStringParam(r, "name")
if _, found := static.Stylesheets[stylesheet]; !found {
html.NotFound(w)
return
diff --git a/ui/subscription_bookmarklet.go b/ui/subscription_bookmarklet.go
index 3aa1392..cba039a 100644
--- a/ui/subscription_bookmarklet.go
+++ b/ui/subscription_bookmarklet.go
@@ -32,7 +32,7 @@ func (c *Controller) Bookmarklet(w http.ResponseWriter, r *http.Request) {
return
}
- bookmarkletURL := request.QueryParam(r, "uri", "")
+ bookmarkletURL := request.QueryStringParam(r, "uri", "")
view.Set("form", form.SubscriptionForm{URL: bookmarkletURL})
view.Set("categories", categories)
diff --git a/ui/user_edit.go b/ui/user_edit.go
index 79e6d4a..f2c1abf 100644
--- a/ui/user_edit.go
+++ b/ui/user_edit.go
@@ -30,12 +30,7 @@ func (c *Controller) EditUser(w http.ResponseWriter, r *http.Request) {
return
}
- userID, err := request.IntParam(r, "userID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ userID := request.RouteInt64Param(r, "userID")
selectedUser, err := c.store.UserByID(userID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/user_remove.go b/ui/user_remove.go
index 4b5440d..981a7a2 100644
--- a/ui/user_remove.go
+++ b/ui/user_remove.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
-package ui // import "miniflux.app/ui"
+package ui // import "miniflux.app/ui"
import (
"net/http"
@@ -26,12 +26,7 @@ func (c *Controller) RemoveUser(w http.ResponseWriter, r *http.Request) {
return
}
- userID, err := request.IntParam(r, "userID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ userID := request.RouteInt64Param(r, "userID")
selectedUser, err := c.store.UserByID(userID)
if err != nil {
html.ServerError(w, err)
diff --git a/ui/user_update.go b/ui/user_update.go
index da28e39..006d49a 100644
--- a/ui/user_update.go
+++ b/ui/user_update.go
@@ -30,12 +30,7 @@ func (c *Controller) UpdateUser(w http.ResponseWriter, r *http.Request) {
return
}
- userID, err := request.IntParam(r, "userID")
- if err != nil {
- html.BadRequest(w, err)
- return
- }
-
+ userID := request.RouteInt64Param(r, "userID")
selectedUser, err := c.store.UserByID(userID)
if err != nil {
html.ServerError(w, err)