From 49c704037bf692de6616f565604fb1afc1bbc4db Mon Sep 17 00:00:00 2001 From: nkanaev Date: Mon, 27 Apr 2026 20:44:24 +0100 Subject: [PATCH] cmd: modernize -fix ./cmd/... --- src/assets/assets.go | 2 +- src/content/sanitizer/sanitizer.go | 31 ++++++------------------------ src/content/scraper/finder.go | 7 +++---- src/parser/rss_test.go | 4 ++-- src/parser/util_test.go | 2 +- src/server/auth/middleware.go | 4 ++-- src/server/fever.go | 26 ++++++++++++------------- src/server/router/context.go | 4 ++-- src/server/routes.go | 19 +++++++++--------- src/server/server.go | 4 ++-- src/storage/feed_test.go | 2 +- src/storage/item.go | 4 ++-- src/storage/settings.go | 14 +++++++------- src/worker/crawler.go | 1 - src/worker/worker.go | 4 ++-- 15 files changed, 53 insertions(+), 75 deletions(-) diff --git a/src/assets/assets.go b/src/assets/assets.go index fa337cd..4e10aac 100644 --- a/src/assets/assets.go +++ b/src/assets/assets.go @@ -51,7 +51,7 @@ func Template(path string) *template.Template { return tmpl } -func Render(path string, writer io.Writer, data interface{}) { +func Render(path string, writer io.Writer, data any) { tmpl := Template(path) tmpl.Execute(writer, data) } diff --git a/src/content/sanitizer/sanitizer.go b/src/content/sanitizer/sanitizer.go index 1b1f6ab..b3d9c97 100644 --- a/src/content/sanitizer/sanitizer.go +++ b/src/content/sanitizer/sanitizer.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "regexp" + "slices" "strconv" "strings" @@ -225,10 +226,8 @@ func hasRequiredAttributes(tagName string, attributes []string) bool { for element, attrs := range elements { if tagName == element { for _, attribute := range attributes { - for _, attr := range attrs { - if attr == attribute { - return true - } + if slices.Contains(attrs, attribute) { + return true } } @@ -285,13 +284,7 @@ func isValidIframeSource(baseURL, src string) bool { return true } - for _, safeDomain := range whitelist { - if safeDomain == domain { - return true - } - } - - return false + return slices.Contains(whitelist, domain) } func getTagAllowList() map[string][]string { @@ -355,13 +348,7 @@ func getTagAllowList() map[string][]string { } func inList(needle string, haystack []string) bool { - for _, element := range haystack { - if element == needle { - return true - } - } - - return false + return slices.Contains(haystack, needle) } func isBlockedTag(tagName string) bool { @@ -371,13 +358,7 @@ func isBlockedTag(tagName string) bool { "style", } - for _, element := range blacklist { - if element == tagName { - return true - } - } - - return false + return slices.Contains(blacklist, tagName) } /* diff --git a/src/content/scraper/finder.go b/src/content/scraper/finder.go index 8722058..9f782ec 100644 --- a/src/content/scraper/finder.go +++ b/src/content/scraper/finder.go @@ -2,6 +2,7 @@ package scraper import ( "net/url" + "slices" "strings" "github.com/nkanaev/yarr/src/content/htmlutil" @@ -22,10 +23,8 @@ func FindFeeds(body string, base string) map[string]string { isFeedLink := func(n *html.Node) bool { if n.Type == html.ElementNode && n.Data == "link" { t := htmlutil.Attr(n, "type") - for _, tt := range linkTypes { - if tt == t { - return true - } + if slices.Contains(linkTypes, t) { + return true } } return false diff --git a/src/parser/rss_test.go b/src/parser/rss_test.go index 4105eb8..df7b981 100644 --- a/src/parser/rss_test.go +++ b/src/parser/rss_test.go @@ -216,7 +216,7 @@ func TestRSSTitleHTMLTags(t *testing.T) { `)) have := []string{feed.Items[0].Title, feed.Items[1].Title} want := []string{"title in p", "very strong title"} - for i := 0; i < len(want); i++ { + for i := range want { if want[i] != have[i] { t.Errorf("title doesn't match\nwant: %#v\nhave: %#v\n", want[i], have[i]) } @@ -241,7 +241,7 @@ func TestRSSIsPermalink(t *testing.T) { URL: "http://example.com/posts/1", }, } - for i := 0; i < len(want); i++ { + for i := range want { if !reflect.DeepEqual(want, have) { t.Errorf("Failed to handle isPermalink\nwant: %#v\nhave: %#v\n", want[i], have[i]) } diff --git a/src/parser/util_test.go b/src/parser/util_test.go index 3cd9ed4..52135b3 100644 --- a/src/parser/util_test.go +++ b/src/parser/util_test.go @@ -46,7 +46,7 @@ func TestSafeXMLReaderPartial1(t *testing.T) { f = NewSafeXMLReader(f) buf := make([]byte, 1) - for i := 0; i < len(want); i++ { + for i := range want { n, err := f.Read(buf) if err != nil { t.Fatal(err) diff --git a/src/server/auth/middleware.go b/src/server/auth/middleware.go index 3362ad9..4450c91 100644 --- a/src/server/auth/middleware.go +++ b/src/server/auth/middleware.go @@ -44,7 +44,7 @@ func (m *Middleware) Handler(c *router.Context) { c.Redirect(rootUrl) return } else { - c.HTML(http.StatusOK, assets.Template("login.html"), map[string]interface{}{ + c.HTML(http.StatusOK, assets.Template("login.html"), map[string]any{ "username": username, "error": "Invalid username/password", "settings": m.DB.GetSettings(), @@ -52,7 +52,7 @@ func (m *Middleware) Handler(c *router.Context) { return } } - c.HTML(http.StatusOK, assets.Template("login.html"), map[string]interface{}{ + c.HTML(http.StatusOK, assets.Template("login.html"), map[string]any{ "settings": m.DB.GetSettings(), }) } diff --git a/src/server/fever.go b/src/server/fever.go index f5c6c03..cc9f191 100644 --- a/src/server/fever.go +++ b/src/server/fever.go @@ -53,7 +53,7 @@ type FeverFavicon struct { Data string `json:"data"` } -func writeFeverJSON(c *router.Context, data map[string]interface{}, lastRefreshed int64) { +func writeFeverJSON(c *router.Context, data map[string]any, lastRefreshed int64) { data["api_version"] = 3 data["auth"] = 1 data["last_refreshed_on_time"] = lastRefreshed @@ -78,7 +78,7 @@ func (s *Server) feverAuth(c *router.Context) bool { if s.Username != "" && s.Password != "" { apiKey := c.Req.FormValue("api_key") apiKey = strings.ToLower(apiKey) - md5HashValue := md5.Sum([]byte(fmt.Sprintf("%s:%s", s.Username, s.Password))) + md5HashValue := md5.Sum(fmt.Appendf(nil, "%s:%s", s.Username, s.Password)) hexMD5HashValue := fmt.Sprintf("%x", md5HashValue[:]) if !auth.StringsEqual(apiKey, hexMD5HashValue) { return false @@ -97,7 +97,7 @@ func formHasValue(values url.Values, value string) bool { func (s *Server) handleFever(c *router.Context) { c.Req.ParseForm() if !s.feverAuth(c) { - c.JSON(http.StatusOK, map[string]interface{}{ + c.JSON(http.StatusOK, map[string]any{ "api_version": 3, "auth": 0, "last_refreshed_on_time": 0, @@ -123,7 +123,7 @@ func (s *Server) handleFever(c *router.Context) { case formHasValue(c.Req.Form, "mark"): s.feverMarkHandler(c) default: - c.JSON(http.StatusOK, map[string]interface{}{ + c.JSON(http.StatusOK, map[string]any{ "api_version": 3, "auth": 1, "last_refreshed_on_time": getLastRefreshedOnTime(s.db.ListHTTPStates()), @@ -168,7 +168,7 @@ func (s *Server) feverGroupsHandler(c *router.Context) { for i, folder := range folders { groups[i] = &FeverGroup{ID: folder.Id, Title: folder.Title} } - writeFeverJSON(c, map[string]interface{}{ + writeFeverJSON(c, map[string]any{ "groups": groups, "feeds_groups": feedGroups(s.db), }, getLastRefreshedOnTime(s.db.ListHTTPStates())) @@ -194,7 +194,7 @@ func (s *Server) feverFeedsHandler(c *router.Context) { LastUpdated: lastUpdated, } } - writeFeverJSON(c, map[string]interface{}{ + writeFeverJSON(c, map[string]any{ "feeds": feverFeeds, "feeds_groups": feedGroups(s.db), }, getLastRefreshedOnTime(httpStates)) @@ -216,7 +216,7 @@ func (s *Server) feverFaviconsHandler(c *router.Context) { favicons[i] = &FeverFavicon{ID: feed.Id, Data: data} } - writeFeverJSON(c, map[string]interface{}{ + writeFeverJSON(c, map[string]any{ "favicons": favicons, }, getLastRefreshedOnTime(s.db.ListHTTPStates())) } @@ -280,15 +280,15 @@ func (s *Server) feverItemsHandler(c *router.Context) { totalItems := s.db.CountItems(storage.ItemFilter{}) - writeFeverJSON(c, map[string]interface{}{ + writeFeverJSON(c, map[string]any{ "items": feverItems, "total_items": totalItems, }, getLastRefreshedOnTime(s.db.ListHTTPStates())) } func (s *Server) feverLinksHandler(c *router.Context) { - writeFeverJSON(c, map[string]interface{}{ - "links": make([]interface{}, 0), + writeFeverJSON(c, map[string]any{ + "links": make([]any, 0), }, getLastRefreshedOnTime(s.db.ListHTTPStates())) } @@ -309,7 +309,7 @@ func (s *Server) feverUnreadItemIDsHandler(c *router.Context) { } itemFilter.After = &items[len(items)-1].Id } - writeFeverJSON(c, map[string]interface{}{ + writeFeverJSON(c, map[string]any{ "unread_item_ids": joinInts(itemIds), }, getLastRefreshedOnTime(s.db.ListHTTPStates())) } @@ -331,7 +331,7 @@ func (s *Server) feverSavedItemIDsHandler(c *router.Context) { } itemFilter.After = &items[len(items)-1].Id } - writeFeverJSON(c, map[string]interface{}{ + writeFeverJSON(c, map[string]any{ "saved_item_ids": joinInts(itemIds), }, getLastRefreshedOnTime(s.db.ListHTTPStates())) } @@ -386,7 +386,7 @@ func (s *Server) feverMarkHandler(c *router.Context) { c.Out.WriteHeader(http.StatusBadRequest) return } - c.JSON(http.StatusOK, map[string]interface{}{ + c.JSON(http.StatusOK, map[string]any{ "api_version": 3, "auth": 1, }) diff --git a/src/server/router/context.go b/src/server/router/context.go index 6e1acfb..ec928b5 100644 --- a/src/server/router/context.go +++ b/src/server/router/context.go @@ -24,7 +24,7 @@ func (c *Context) Next() { c.chain[c.index](c) } -func (c *Context) JSON(status int, data interface{}) { +func (c *Context) JSON(status int, data any) { body, err := json.Marshal(data) if err != nil { log.Fatal(err) @@ -35,7 +35,7 @@ func (c *Context) JSON(status int, data interface{}) { c.Out.Write([]byte("\n")) } -func (c *Context) HTML(status int, tmpl *template.Template, data interface{}) { +func (c *Context) HTML(status int, tmpl *template.Template, data any) { c.Out.Header().Set("Content-Type", "text/html") c.Out.WriteHeader(status) tmpl.Execute(c.Out, data) diff --git a/src/server/routes.go b/src/server/routes.go index 37c1368..c040fbe 100644 --- a/src/server/routes.go +++ b/src/server/routes.go @@ -64,7 +64,7 @@ func (s *Server) handler() http.Handler { } func (s *Server) handleIndex(c *router.Context) { - c.HTML(http.StatusOK, assets.Template("index.html"), map[string]interface{}{ + c.HTML(http.StatusOK, assets.Template("index.html"), map[string]any{ "settings": s.db.GetSettings(), "authenticated": s.Username != "" && s.Password != "", }) @@ -82,14 +82,14 @@ func (s *Server) handleStatic(c *router.Context) { } func (s *Server) handleManifest(c *router.Context) { - c.JSON(http.StatusOK, map[string]interface{}{ + c.JSON(http.StatusOK, map[string]any{ "$schema": "https://json.schemastore.org/web-manifest-combined.json", "name": "yarr!", "short_name": "yarr", "description": "yet another rss reader", "display": "standalone", "start_url": "/" + strings.TrimPrefix(s.BasePath, "/"), - "icons": []map[string]interface{}{ + "icons": []map[string]any{ { "src": s.BasePath + "/static/graphicarts/favicon.png", "sizes": "64x64", @@ -100,7 +100,7 @@ func (s *Server) handleManifest(c *router.Context) { } func (s *Server) handleStatus(c *router.Context) { - c.JSON(http.StatusOK, map[string]interface{}{ + c.JSON(http.StatusOK, map[string]any{ "running": s.worker.FeedsPending(), "stats": s.db.FeedStats(), }) @@ -239,7 +239,7 @@ func (s *Server) handleFeedList(c *router.Context) { case len(result.Sources) > 0: c.JSON( http.StatusOK, - map[string]interface{}{"status": "multiple", "choice": result.Sources}, + map[string]any{"status": "multiple", "choice": result.Sources}, ) case result.Feed != nil: feed := s.db.CreateFeed( @@ -257,7 +257,7 @@ func (s *Server) handleFeedList(c *router.Context) { } s.worker.FindFeedFavicon(*feed) - c.JSON(http.StatusOK, map[string]interface{}{ + c.JSON(http.StatusOK, map[string]any{ "status": "success", "feed": feed, }) @@ -279,7 +279,7 @@ func (s *Server) handleFeed(c *router.Context) { c.Out.WriteHeader(http.StatusBadRequest) return } - body := make(map[string]interface{}) + body := make(map[string]any) if err := json.NewDecoder(c.Req.Body).Decode(&body); err != nil { log.Print(err) c.Out.WriteHeader(http.StatusBadRequest) @@ -391,7 +391,7 @@ func (s *Server) handleItemList(c *router.Context) { items[i].Title = htmlutil.TruncateText(text, 140) } } - c.JSON(http.StatusOK, map[string]interface{}{ + c.JSON(http.StatusOK, map[string]any{ "list": items, "has_more": hasMore, }) @@ -415,7 +415,7 @@ func (s *Server) handleSettings(c *router.Context) { if c.Req.Method == "GET" { c.JSON(http.StatusOK, s.db.GetSettings()) } else if c.Req.Method == "PUT" { - settings := make(map[string]interface{}) + settings := make(map[string]any) if err := json.NewDecoder(c.Req.Body).Decode(&settings); err != nil { c.Out.WriteHeader(http.StatusBadRequest) return @@ -472,7 +472,6 @@ func (s *Server) handleOPMLExport(c *router.Context) { feedsByFolderID := make(map[int64][]*storage.Feed) for _, feed := range s.db.ListFeeds() { - feed := feed if feed.FolderId == nil { doc.Feeds = append(doc.Feeds, opml.Feed{ Title: feed.Title, diff --git a/src/server/server.go b/src/server/server.go index a98784a..f3e571e 100644 --- a/src/server/server.go +++ b/src/server/server.go @@ -16,7 +16,7 @@ type Server struct { Addr string db *storage.Storage worker *worker.Worker - cache map[string]interface{} + cache map[string]any cache_mutex *sync.Mutex BasePath string @@ -34,7 +34,7 @@ func NewServer(db *storage.Storage, addr string) *Server { db: db, Addr: addr, worker: worker.NewWorker(db), - cache: make(map[string]interface{}), + cache: make(map[string]any), cache_mutex: &sync.Mutex{}, } } diff --git a/src/storage/feed_test.go b/src/storage/feed_test.go index 33aee7c..27a16fd 100644 --- a/src/storage/feed_test.go +++ b/src/storage/feed_test.go @@ -24,7 +24,7 @@ func TestCreateFeedSameLink(t *testing.T) { t.Fatal("expected feed") } - for i := 0; i < 10; i++ { + for range 10 { db.CreateFeed("title", "", "", "http://example2.com/feed.xml", nil) } diff --git a/src/storage/item.go b/src/storage/item.go index 474c8b9..f96a2eb 100644 --- a/src/storage/item.go +++ b/src/storage/item.go @@ -169,9 +169,9 @@ func (s *Storage) CreateItems(items []Item) bool { return true } -func listQueryPredicate(filter ItemFilter, newestFirst bool) (string, []interface{}) { +func listQueryPredicate(filter ItemFilter, newestFirst bool) (string, []any) { cond := make([]string, 0) - args := make([]interface{}, 0) + args := make([]any, 0) if filter.FolderID != nil { cond = append(cond, "i.feed_id in (select id from feeds where folder_id = :folder_id)") args = append(args, sql.Named("folder_id", *filter.FolderID)) diff --git a/src/storage/settings.go b/src/storage/settings.go index 14eacc5..21daac9 100644 --- a/src/storage/settings.go +++ b/src/storage/settings.go @@ -6,8 +6,8 @@ import ( "log" ) -func settingsDefaults() map[string]interface{} { - return map[string]interface{}{ +func settingsDefaults() map[string]any { + return map[string]any{ "filter": "", "feed": "", "feed_list_width": 300, @@ -20,7 +20,7 @@ func settingsDefaults() map[string]interface{} { } } -func (s *Storage) GetSettingsValue(key string) interface{} { +func (s *Storage) GetSettingsValue(key string) any { row := s.db.QueryRow(`select val from settings where key=:key`, sql.Named("key", key)) if row == nil { return settingsDefaults()[key] @@ -30,7 +30,7 @@ func (s *Storage) GetSettingsValue(key string) interface{} { if len(val) == 0 { return nil } - var valDecoded interface{} + var valDecoded any if err := json.Unmarshal([]byte(val), &valDecoded); err != nil { log.Print(err) return nil @@ -48,7 +48,7 @@ func (s *Storage) GetSettingsValueInt64(key string) int64 { return 0 } -func (s *Storage) GetSettings() map[string]interface{} { +func (s *Storage) GetSettings() map[string]any { result := settingsDefaults() rows, err := s.db.Query(`select key, val from settings;`) if err != nil { @@ -58,7 +58,7 @@ func (s *Storage) GetSettings() map[string]interface{} { for rows.Next() { var key string var val []byte - var valDecoded interface{} + var valDecoded any rows.Scan(&key, &val) if err = json.Unmarshal([]byte(val), &valDecoded); err != nil { @@ -70,7 +70,7 @@ func (s *Storage) GetSettings() map[string]interface{} { return result } -func (s *Storage) UpdateSettings(kv map[string]interface{}) bool { +func (s *Storage) UpdateSettings(kv map[string]any) bool { defaults := settingsDefaults() for key, val := range kv { if defaults[key] == nil { diff --git a/src/worker/crawler.go b/src/worker/crawler.go index eb2f0a7..699f1f8 100644 --- a/src/worker/crawler.go +++ b/src/worker/crawler.go @@ -141,7 +141,6 @@ func findFavicon(siteUrl, feedUrl string) (*[]byte, error) { func ConvertItems(items []parser.Item, feed storage.Feed) []storage.Item { result := make([]storage.Item, len(items)) for i, item := range items { - item := item mediaLinks := make(storage.MediaLinks, 0) for _, link := range item.MediaLinks { mediaLinks = append(mediaLinks, storage.MediaLink(link)) diff --git a/src/worker/worker.go b/src/worker/worker.go index bdf066e..c64cd97 100644 --- a/src/worker/worker.go +++ b/src/worker/worker.go @@ -113,14 +113,14 @@ func (w *Worker) refresher(feeds []storage.Feed) { srcqueue := make(chan storage.Feed, len(feeds)) dstqueue := make(chan []storage.Item) - for i := 0; i < NUM_WORKERS; i++ { + for range NUM_WORKERS { go w.worker(srcqueue, dstqueue) } for _, feed := range feeds { srcqueue <- feed } - for i := 0; i < len(feeds); i++ { + for range feeds { items := <-dstqueue if len(items) > 0 { w.db.CreateItems(items)