diff --git a/backend/_example/memory_store/accessor/data.go b/backend/_example/memory_store/accessor/data.go index 6ac74465..2fd1579c 100644 --- a/backend/_example/memory_store/accessor/data.go +++ b/backend/_example/memory_store/accessor/data.go @@ -251,11 +251,11 @@ func (m *MemData) Flag(req engine.FlagRequest) (val bool, err error) { // ListFlags get list of flagged keys, like blocked & verified user // works for full locator (post flags) or with userID -func (m *MemData) ListFlags(req engine.FlagRequest) (res []interface{}, err error) { +func (m *MemData) ListFlags(req engine.FlagRequest) (res []any, err error) { m.mu.RLock() defer m.mu.RUnlock() - res = []interface{}{} + res = []any{} switch req.Flag { case engine.Verified: diff --git a/backend/_example/memory_store/accessor/data_test.go b/backend/_example/memory_store/accessor/data_test.go index 9c3aea23..95e03e36 100644 --- a/backend/_example/memory_store/accessor/data_test.go +++ b/backend/_example/memory_store/accessor/data_test.go @@ -198,7 +198,7 @@ func TestMemData_FindForUserPagination(t *testing.T) { } // write 200 comments - for i := 0; i < 200; i++ { + for i := range 200 { c.ID = fmt.Sprintf("idd-%d", i) c.Text = fmt.Sprintf("text #%d", i) c.Timestamp = time.Date(2017, 12, 20, 15, 18, i, 0, time.Local) @@ -484,7 +484,7 @@ func TestMemData_FlagVerified(t *testing.T) { func TestMemData_FlagListVerified(t *testing.T) { b := prepMem(t) - toIDs := func(inp []interface{}) (res []string) { + toIDs := func(inp []any) (res []string) { res = make([]string, len(inp)) for i, v := range inp { vv, ok := v.(string) @@ -530,7 +530,7 @@ func TestMemData_FlagListBlocked(t *testing.T) { return err } - toBlocked := func(inp []interface{}) (res []store.BlockedUser) { + toBlocked := func(inp []any) (res []store.BlockedUser) { res = make([]store.BlockedUser, len(inp)) for i, v := range inp { vv, ok := v.(store.BlockedUser) diff --git a/backend/_example/memory_store/server/admin.go b/backend/_example/memory_store/server/admin.go index 70b8441e..9b29df55 100644 --- a/backend/_example/memory_store/server/admin.go +++ b/backend/_example/memory_store/server/admin.go @@ -73,7 +73,7 @@ func (s *RPC) admEnabledHndl(id uint64, params json.RawMessage) (rr jrpc.Respons // onEvent returns nothing, callback to OnEvent func (s *RPC) admEventHndl(id uint64, params json.RawMessage) (rr jrpc.Response) { var siteID string - var ps []interface{} + var ps []any if err := json.Unmarshal(params, &ps); err != nil { return jrpc.Response{Error: err.Error()} } diff --git a/backend/_example/memory_store/server/data_test.go b/backend/_example/memory_store/server/data_test.go index b1d2fd3d..04db5467 100644 --- a/backend/_example/memory_store/server/data_test.go +++ b/backend/_example/memory_store/server/data_test.go @@ -217,7 +217,7 @@ func TestRPC_listFlagsHndl(t *testing.T) { flags, err = re.ListFlags(verifyFlagReq) require.NoError(t, err) - assert.Equal(t, []interface{}{"u1"}, flags) + assert.Equal(t, []any{"u1"}, flags) verifiedUsers := make([]string, 0, len(flags)) for _, v := range flags { verifiedUsers = append(verifiedUsers, v.(string)) diff --git a/backend/_example/memory_store/server/rpc_test.go b/backend/_example/memory_store/server/rpc_test.go index 706a7b83..a5a0a2df 100644 --- a/backend/_example/memory_store/server/rpc_test.go +++ b/backend/_example/memory_store/server/rpc_test.go @@ -21,7 +21,7 @@ import ( ) func chooseRandomUnusedPort() (port int) { - for i := 0; i < 10; i++ { + for range 10 { port = 40000 + int(rand.Int31n(10000)) if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil { _ = ln.Close() @@ -34,7 +34,7 @@ func chooseRandomUnusedPort() (port int) { func waitForHTTPServerStart(port int) { // wait for up to 3 seconds for server to start before returning it client := http.Client{Timeout: time.Second} - for i := 0; i < 300; i++ { + for range 300 { time.Sleep(time.Millisecond * 10) if resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port)); err == nil { _ = resp.Body.Close() diff --git a/backend/app/cmd/cleanup.go b/backend/app/cmd/cleanup.go index 3a4dc2e1..fba237ac 100644 --- a/backend/app/cmd/cleanup.go +++ b/backend/app/cmd/cleanup.go @@ -179,7 +179,7 @@ func (cc *CleanupCommand) listComments(postURL string) ([]store.Comment, error) commentsWithInfo := struct { Comments []store.Comment `json:"comments"` - Info store.PostInfo `json:"info,omitempty"` + Info store.PostInfo `json:"info"` }{} if err = json.NewDecoder(r.Body).Decode(&commentsWithInfo); err != nil { diff --git a/backend/app/cmd/cleanup_test.go b/backend/app/cmd/cleanup_test.go index 4a102874..f4145332 100644 --- a/backend/app/cmd/cleanup_test.go +++ b/backend/app/cmd/cleanup_test.go @@ -173,7 +173,7 @@ func cleanupRoutes(t *testing.T, r *chi.Mux, c *cleanedComments) { commentsWithInfo := struct { Comments []store.Comment `json:"comments"` - Info store.PostInfo `json:"info,omitempty"` + Info store.PostInfo `json:"info"` }{} switch r.URL.Query().Get("url") { diff --git a/backend/app/cmd/server.go b/backend/app/cmd/server.go index f463d1cb..d9ca50a4 100644 --- a/backend/app/cmd/server.go +++ b/backend/app/cmd/server.go @@ -11,6 +11,7 @@ import ( "os/signal" "path" "regexp" + "slices" "strings" "syscall" "time" @@ -479,12 +480,7 @@ func stringsSetAndDifferent(s1, s2 string) bool { } func contains(s string, a []string) bool { - for _, t := range a { - if t == s { - return true - } - } - return false + return slices.Contains(a, s) } // newServerApp prepares application and return it with all active parts diff --git a/backend/app/cmd/server_test.go b/backend/app/cmd/server_test.go index 176ba583..42ea8842 100644 --- a/backend/app/cmd/server_test.go +++ b/backend/app/cmd/server_test.go @@ -789,7 +789,7 @@ func Test_getAllowedDomains(t *testing.T) { } func chooseRandomUnusedPort() (port int) { - for i := 0; i < 10; i++ { + for range 10 { port = 40000 + int(rand.Int31n(10000)) if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil { _ = ln.Close() @@ -803,7 +803,7 @@ func waitForHTTPServerStart(port int) { // wait for up to 3 seconds for server to start before returning it client := http.Client{Timeout: time.Second} defer client.CloseIdleConnections() - for i := 0; i < 300; i++ { + for range 300 { time.Sleep(time.Millisecond * 10) if resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port)); err == nil { _ = resp.Body.Close() @@ -814,7 +814,7 @@ func waitForHTTPServerStart(port int) { func waitForHTTPSServerStart(port int) { // wait for up to 3 seconds for HTTPS server to start - for i := 0; i < 300; i++ { + for range 300 { time.Sleep(time.Millisecond * 10) conn, _ := net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", port), time.Millisecond*10) if conn != nil { diff --git a/backend/app/main.go b/backend/app/main.go index c163ad1f..3bf5dfff 100644 --- a/backend/app/main.go +++ b/backend/app/main.go @@ -92,10 +92,7 @@ func logDeprecatedParams(params []cmd.DeprecatedFlag) { func getDump() string { maxSize := 5 * 1024 * 1024 stacktrace := make([]byte, maxSize) - length := runtime.Stack(stacktrace, true) - if length > maxSize { - length = maxSize - } + length := min(runtime.Stack(stacktrace, true), maxSize) return string(stacktrace[:length]) } diff --git a/backend/app/main_test.go b/backend/app/main_test.go index bb67eeac..9e968ff5 100644 --- a/backend/app/main_test.go +++ b/backend/app/main_test.go @@ -130,7 +130,7 @@ func TestGetDump(t *testing.T) { } func chooseRandomUnusedPort() (port int) { - for i := 0; i < 10; i++ { + for range 10 { port = 40000 + int(rand.Int31n(10000)) if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil { _ = ln.Close() @@ -144,7 +144,7 @@ func waitForHTTPServerStart(port int) { // wait for up to 10 seconds for server to start before returning it client := http.Client{Timeout: time.Second} defer client.CloseIdleConnections() - for i := 0; i < 100; i++ { + for range 100 { time.Sleep(time.Millisecond * 100) if resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port)); err == nil { _ = resp.Body.Close() diff --git a/backend/app/migrator/commento.go b/backend/app/migrator/commento.go index af48dcf7..b33f2333 100644 --- a/backend/app/migrator/commento.go +++ b/backend/app/migrator/commento.go @@ -48,7 +48,7 @@ type commentoCommenter struct { Link string `json:"link"` Photo string `json:"photo"` Provider string `json:"provider,omitempty"` - JoinDate time.Time `json:"joinDate,omitempty"` + JoinDate time.Time `json:"joinDate"` IsModerator bool `json:"isModerator"` } diff --git a/backend/app/migrator/mapper.go b/backend/app/migrator/mapper.go index 7d215ff9..1235b716 100644 --- a/backend/app/migrator/mapper.go +++ b/backend/app/migrator/mapper.go @@ -38,7 +38,7 @@ func (u *URLMapper) loadRules(reader io.Reader) error { u.rules = make(map[string]string) - for _, row := range strings.Split(rulesText, "\n") { + for row := range strings.SplitSeq(rulesText, "\n") { row = strings.TrimSpace(row) urls := strings.Split(row, " ") if len(urls) != 2 { @@ -64,8 +64,8 @@ func (u *URLMapper) URL(url string) string { } oldURL = strings.TrimSuffix(oldURL, "*") newURL = strings.TrimSuffix(newURL, "*") - if strings.HasPrefix(url, oldURL) { - return newURL + strings.TrimPrefix(url, oldURL) + if after, ok := strings.CutPrefix(url, oldURL); ok { + return newURL + after } } // search failed, return given url diff --git a/backend/app/migrator/native_test.go b/backend/app/migrator/native_test.go index 88db1c2a..779d6ada 100644 --- a/backend/app/migrator/native_test.go +++ b/backend/app/migrator/native_test.go @@ -162,7 +162,7 @@ func TestNative_ImportManyWithError(t *testing.T) { buf := &bytes.Buffer{} buf.WriteString(`{"version":1, "users":[], "posts":[]}` + "\n") - for i := 0; i < 100; i++ { + for i := range 100 { fmt.Fprintf(buf, goodRec, i) } buf.WriteString("{}\n") diff --git a/backend/app/notify/notify_test.go b/backend/app/notify/notify_test.go index 73184f09..394e2eb1 100644 --- a/backend/app/notify/notify_test.go +++ b/backend/app/notify/notify_test.go @@ -96,7 +96,7 @@ func TestService_Many(t *testing.T) { s := NewService(nil, 5, d1, d2) assert.NotNil(t, s) - for i := 0; i < 10; i++ { + for i := range 10 { s.Submit(Request{Comment: store.Comment{ID: fmt.Sprintf("%d", 100+i)}}) s.SubmitVerification(VerificationRequest{User: fmt.Sprintf("%d", 100+i)}) time.Sleep(time.Millisecond * time.Duration(rand.Int31n(20))) diff --git a/backend/app/providers/telegram.go b/backend/app/providers/telegram.go index 86a8d8bb..be6b9301 100644 --- a/backend/app/providers/telegram.go +++ b/backend/app/providers/telegram.go @@ -15,7 +15,7 @@ import ( ) type tgRequester interface { - Request(ctx context.Context, method string, b []byte, data interface{}) error + Request(ctx context.Context, method string, b []byte, data any) error } // TGUpdatesReceiver used to dispatch telegram updates to multiple receivers diff --git a/backend/app/providers/telegram_test.go b/backend/app/providers/telegram_test.go index 67b332d5..7edc23c4 100644 --- a/backend/app/providers/telegram_test.go +++ b/backend/app/providers/telegram_test.go @@ -39,7 +39,7 @@ type mockTGRequester struct { t *testing.T } -func (m *mockTGRequester) Request(_ context.Context, _ string, _ []byte, data interface{}) error { +func (m *mockTGRequester) Request(_ context.Context, _ string, _ []byte, data any) error { if m.hit < 2 { m.hit++ assert.NoError(m.t, json.Unmarshal([]byte(getUpdatesResp), data)) diff --git a/backend/app/rest/api/admin_test.go b/backend/app/rest/api/admin_test.go index bcad5d21..663efd88 100644 --- a/backend/app/rest/api/admin_test.go +++ b/backend/app/rest/api/admin_test.go @@ -87,7 +87,7 @@ func TestAdmin_Delete(t *testing.T) { // check count updated res, code = get(t, ts.URL+"/api/v1/count?site=remark42&url=https://radio-t.com/blah") assert.Equal(t, http.StatusOK, code) - b := map[string]interface{}{} + b := map[string]any{} err = json.Unmarshal([]byte(res), &b) assert.NoError(t, err) t.Logf("%#v", b) @@ -718,7 +718,7 @@ func TestAdmin_DeleteMeRequest(t *testing.T) { User: &token.User{ ID: "user1", Picture: "pic.image", - Attributes: map[string]interface{}{ + Attributes: map[string]any{ "delete_me": true, }, }, @@ -786,7 +786,7 @@ func TestAdmin_DeleteMeRequestFailed(t *testing.T) { }, User: &token.User{ ID: "provider1_user1", - Attributes: map[string]interface{}{ + Attributes: map[string]any{ "delete_me": true, }, }, diff --git a/backend/app/rest/api/migrator_test.go b/backend/app/rest/api/migrator_test.go index d4a4c7ac..ab1a3f42 100644 --- a/backend/app/rest/api/migrator_test.go +++ b/backend/app/rest/api/migrator_test.go @@ -276,8 +276,8 @@ func TestMigrator_ImportDouble(t *testing.T) { "picture":"/api/v1/avatar/remark.image","profile":"https://remark42.com","admin":true, "ip":"ae12fe3b5f129b5cc4cdd2b136b7b7947c4d2741"},"locator":{"site":"remark42","url":"https://radio-t.com/blah1"},"score":0, "votes":{},"time":"2018-04-30T01:37:00.849053725-05:00"}` - recs := []string{} - for i := 0; i < 50; i++ { + recs := make([]string, 0, 50) + for i := range 50 { recs = append(recs, fmt.Sprintf(tmpl, i)) } r := strings.NewReader(`{"version":1}` + strings.Join(recs, "\n")) // reader with 10k records @@ -329,7 +329,7 @@ func TestMigrator_ImportWaitExpired(t *testing.T) { "votes":{},"time":"2018-04-30T01:37:00.849053725-05:00"}` nRecs := 50 recs := make([]string, 0, nRecs) - for i := 0; i < nRecs; i++ { + for i := range nRecs { recs = append(recs, fmt.Sprintf(tmpl, i)) } r := strings.NewReader(`{"version":1}` + strings.Join(recs, "\n")) // reader with `nRecs` records diff --git a/backend/app/rest/api/rest.go b/backend/app/rest/api/rest.go index e2c2adf4..785b7d71 100644 --- a/backend/app/rest/api/rest.go +++ b/backend/app/rest/api/rest.go @@ -96,12 +96,12 @@ const lastCommentsScope = "last" type commentsWithInfo struct { Comments []store.Comment `json:"comments"` - Info store.PostInfo `json:"info,omitempty"` + Info store.PostInfo `json:"info"` } type treeWithInfo struct { *service.Tree - Info store.PostInfo `json:"info,omitempty"` + Info store.PostInfo `json:"info"` } // Run the lister and request's router, activate rest server @@ -504,7 +504,7 @@ func addFileServer(r chi.Router, embedFS embed.FS, webRoot, version string) { }) } -func encodeJSONWithHTML(v interface{}) ([]byte, error) { +func encodeJSONWithHTML(v any) ([]byte, error) { buf := &bytes.Buffer{} enc := json.NewEncoder(buf) enc.SetEscapeHTML(false) diff --git a/backend/app/rest/api/rest_private.go b/backend/app/rest/api/rest_private.go index 1b51f545..24d887d7 100644 --- a/backend/app/rest/api/rest_private.go +++ b/backend/app/rest/api/rest_private.go @@ -579,7 +579,7 @@ func (s *private) emailUnsubscribeCtrl(w http.ResponseWriter, r *http.Request) { } // MustExecute behaves like template.Execute, but panics if an error occurs. - MustExecute := func(tmpl *template.Template, wr io.Writer, data interface{}) { + MustExecute := func(tmpl *template.Template, wr io.Writer, data any) { if err := tmpl.Execute(wr, data); err != nil { panic(err) } @@ -670,7 +670,7 @@ func (s *private) userAllDataCtrl(w http.ResponseWriter, r *http.Request) { merr = multierror.Append(merr, write([]byte(`, "comments":`))) // send comments prefix // get comments in 100 in each paginated request - for i := 0; i < 100; i++ { + for i := range 100 { comments, errUser := s.dataService.User(siteID, user.ID, 100, i*100, rest.GetUserOrEmpty(r)) if errUser != nil { rest.SendErrorJSON(w, r, http.StatusInternalServerError, errUser, "can't get user comments", rest.ErrInternal) @@ -711,7 +711,7 @@ func (s *private) deleteMeCtrl(w http.ResponseWriter, r *http.Request) { User: &token.User{ ID: user.ID, Name: user.Name, - Attributes: map[string]interface{}{ + Attributes: map[string]any{ "delete_me": true, // prevents this token from being used for login }, }, diff --git a/backend/app/rest/api/rest_private_test.go b/backend/app/rest/api/rest_private_test.go index edcf34e7..4cfc3331 100644 --- a/backend/app/rest/api/rest_private_test.go +++ b/backend/app/rest/api/rest_private_test.go @@ -49,7 +49,7 @@ func TestRest_Create(t *testing.T) { c := R.JSON{} err = json.Unmarshal(b, &c) assert.NoError(t, err) - loc := c["locator"].(map[string]interface{}) + loc := c["locator"].(map[string]any) assert.Equal(t, "remark42", loc["site"]) assert.Equal(t, "https://radio-t.com/blah1", loc["url"]) assert.True(t, len(c["id"].(string)) > 8) @@ -71,7 +71,7 @@ func TestRest_CreateFilteredCode(t *testing.T) { c := R.JSON{} err = json.Unmarshal(b, &c) require.NoError(t, err, string(b)) - loc := c["locator"].(map[string]interface{}) + loc := c["locator"].(map[string]any) assert.Equal(t, "remark42", loc["site"]) assert.Equal(t, "https://radio-t.com/blah1", loc["url"]) assert.Equal(t, "`foo`", c["orig"]) @@ -123,7 +123,7 @@ func TestRest_CreateAndPreviewWithImage(t *testing.T) { require.NoError(t, err, string(b)) assert.NotContains(t, c["text"], pngServer.URL) assert.Contains(t, c["text"], srv.RemarkURL) - loc := c["locator"].(map[string]interface{}) + loc := c["locator"].(map[string]any) assert.Equal(t, "remark42", loc["site"]) assert.Equal(t, "https://radio-t.com/blah1", loc["url"]) assert.True(t, len(c["id"].(string)) > 8) @@ -1456,7 +1456,7 @@ func TestRest_UserAllDataManyComments(t *testing.T) { c := store.Comment{User: user, Text: "test test #1", Locator: store.Locator{SiteID: "remark42", URL: "https://radio-t.com/blah1"}, Timestamp: time.Date(2018, 5, 27, 1, 14, 10, 0, time.Local)} - for i := 0; i < 51; i++ { + for i := range 51 { c.ID = fmt.Sprintf("id-%03d", i) c.Timestamp = c.Timestamp.Add(time.Second) _, err := srv.DataService.Create(c) diff --git a/backend/app/rest/api/rest_public_test.go b/backend/app/rest/api/rest_public_test.go index b14cf615..0f97e28b 100644 --- a/backend/app/rest/api/rest_public_test.go +++ b/backend/app/rest/api/rest_public_test.go @@ -930,7 +930,7 @@ func TestRest_Config(t *testing.T) { err := json.Unmarshal([]byte(body), &j) assert.NoError(t, err) assert.Equal(t, 300.0, j["edit_duration"]) - assert.EqualValues(t, []interface{}{"a1", "a2"}, j["admins"]) + assert.EqualValues(t, []any{"a1", "a2"}, j["admins"]) assert.Equal(t, "admin@remark-42.com", j["admin_email"]) assert.Equal(t, 4000.0, j["max_comment_size"]) assert.Equal(t, -5.0, j["low_score"]) diff --git a/backend/app/rest/api/rest_test.go b/backend/app/rest/api/rest_test.go index 7dd66984..1cc848c1 100644 --- a/backend/app/rest/api/rest_test.go +++ b/backend/app/rest/api/rest_test.go @@ -437,7 +437,7 @@ func Test_validEmailAuth(t *testing.T) { // randomPath pick a file or folder name which is not in use for sure func randomPath(tempDir, basename, suffix string) (string, error) { - for i := 0; i < 10; i++ { + for range 10 { fname := fmt.Sprintf("/%s/%s-%d%s", tempDir, basename, rand.Int31(), suffix) fmt.Printf("fname %q", fname) _, err := os.Stat(fname) @@ -667,7 +667,7 @@ func requireAdminOnly(t *testing.T, req *http.Request) { } func chooseRandomUnusedPort() (port int) { - for i := 0; i < 10; i++ { + for range 10 { port = 40000 + int(rand.Int31n(10000)) if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil { _ = ln.Close() @@ -679,7 +679,7 @@ func chooseRandomUnusedPort() (port int) { func waitForHTTPSServerStart(port int) { // wait for up to 3 seconds for HTTPS server to start - for i := 0; i < 300; i++ { + for range 300 { time.Sleep(time.Millisecond * 10) conn, _ := net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", port), time.Millisecond*10) if conn != nil { diff --git a/backend/app/rest/httperrors.go b/backend/app/rest/httperrors.go index 88ed3369..730bbd2b 100644 --- a/backend/app/rest/httperrors.go +++ b/backend/app/rest/httperrors.go @@ -51,7 +51,7 @@ type errTmplData struct { // error code is not included in render as it is intended for UI developers and not for the users func SendErrorHTML(w http.ResponseWriter, r *http.Request, httpStatusCode int, err error, details string, errCode int) { // MustExecute behaves like template.Execute, but panics if an error occurs. - MustExecute := func(tmpl *template.Template, wr io.Writer, data interface{}) { + MustExecute := func(tmpl *template.Template, wr io.Writer, data any) { if err = tmpl.Execute(wr, data); err != nil { panic(err) } diff --git a/backend/app/rest/proxy/image_test.go b/backend/app/rest/proxy/image_test.go index 1abd54e2..69f10dec 100644 --- a/backend/app/rest/proxy/image_test.go +++ b/backend/app/rest/proxy/image_test.go @@ -212,7 +212,7 @@ func TestImage_RoutesCachingImage(t *testing.T) { func TestImage_RoutesUsingCachedImage(t *testing.T) { // in order to validate that cached data used cache "will return" some other data from what http server would - testImage := []byte(fmt.Sprintf("%256s", "X")) + testImage := fmt.Appendf(nil, "%256s", "X") imageStore := image.StoreMock{LoadFunc: func(string) ([]byte, error) { return testImage, nil }} diff --git a/backend/app/rest/user.go b/backend/app/rest/user.go index 44963333..0ef15cd8 100644 --- a/backend/app/rest/user.go +++ b/backend/app/rest/user.go @@ -56,7 +56,7 @@ func SetUserInfo(r *http.Request, user store.User) *http.Request { Picture: user.Picture, IP: user.IP, Audience: user.SiteID, - Attributes: map[string]interface{}{ + Attributes: map[string]any{ "blocked": user.Blocked, "verified": user.Verified, }, diff --git a/backend/app/store/comment.go b/backend/app/store/comment.go index 8a5b89fd..108b4ce5 100644 --- a/backend/app/store/comment.go +++ b/backend/app/store/comment.go @@ -50,8 +50,8 @@ type PostInfo struct { CountLeft int `json:"count_left"` // used only with returning search results limited by number, otherwise zero LastComment string `json:"last_comment,omitempty"` // used only with returning search results limited by number ReadOnly bool `json:"read_only,omitempty" bson:"read_only,omitempty"` // can be attached to site-wide comments but won't be set then - FirstTS time.Time `json:"first_time,omitempty" bson:"first_time,omitempty"` - LastTS time.Time `json:"last_time,omitempty" bson:"last_time,omitempty"` + FirstTS time.Time `json:"first_time" bson:"first_time,omitempty"` + LastTS time.Time `json:"last_time" bson:"last_time,omitempty"` } // BlockedUser holds id and ts for blocked user diff --git a/backend/app/store/engine/bolt.go b/backend/app/store/engine/bolt.go index 38b8e29b..0d49111a 100644 --- a/backend/app/store/engine/bolt.go +++ b/backend/app/store/engine/bolt.go @@ -346,13 +346,13 @@ func (b *BoltDB) Info(req InfoRequest) ([]store.PostInfo, error) { // ListFlags get list of flagged keys, like blocked & verified user // works for full locator (post flags) or with userID -func (b *BoltDB) ListFlags(req FlagRequest) (res []interface{}, err error) { +func (b *BoltDB) ListFlags(req FlagRequest) (res []any, err error) { bdb, e := b.db(req.Locator.SiteID) if e != nil { return nil, e } - res = []interface{}{} + res = []any{} switch req.Flag { case Verified: err = bdb.View(func(tx *bolt.Tx) error { @@ -957,7 +957,7 @@ func (b *BoltDB) getUserBucket(tx *bolt.Tx, userID string) (*bolt.Bucket, error) } // save marshaled value to key for bucket. Should run in update tx -func (b *BoltDB) save(bkt *bolt.Bucket, key string, value interface{}) (err error) { +func (b *BoltDB) save(bkt *bolt.Bucket, key string, value any) (err error) { if value == nil { return fmt.Errorf("can't save nil value for %s", key) } @@ -972,7 +972,7 @@ func (b *BoltDB) save(bkt *bolt.Bucket, key string, value interface{}) (err erro } // load and unmarshal json value by key from bucket. Should run in view tx -func (b *BoltDB) load(bkt *bolt.Bucket, key string, res interface{}) error { +func (b *BoltDB) load(bkt *bolt.Bucket, key string, res any) error { value := bkt.Get([]byte(key)) if value == nil { return fmt.Errorf("no value for %s", key) @@ -1027,7 +1027,7 @@ func (b *BoltDB) db(siteID string) (*bolt.DB, error) { // makeRef creates reference combining url and comment id func (b *BoltDB) makeRef(comment store.Comment) []byte { - return []byte(fmt.Sprintf("%s!!%s", comment.Locator.URL, comment.ID)) + return fmt.Appendf(nil, "%s!!%s", comment.Locator.URL, comment.ID) } // parseRef gets parts of reference diff --git a/backend/app/store/engine/bolt_test.go b/backend/app/store/engine/bolt_test.go index 85bdce69..ebbe1cd0 100644 --- a/backend/app/store/engine/bolt_test.go +++ b/backend/app/store/engine/bolt_test.go @@ -236,7 +236,7 @@ func TestBoltDB_FindForUserPagination(t *testing.T) { } // write 200 comments - for i := 0; i < 200; i++ { + for i := range 200 { c.ID = fmt.Sprintf("id-%d", i) c.Text = fmt.Sprintf("text #%d", i) c.Timestamp = time.Date(2017, 12, 20, 15, 18, i, 0, time.Local) @@ -540,7 +540,7 @@ func TestBolt_FlagListVerified(t *testing.T) { b, teardown := prep(t) defer teardown() - toIDs := func(inp []interface{}) (res []string) { + toIDs := func(inp []any) (res []string) { res = make([]string, len(inp)) for i, v := range inp { vv, ok := v.(string) @@ -580,7 +580,7 @@ func TestBolt_FlagListBlocked(t *testing.T) { return err } - toBlocked := func(inp []interface{}) (res []store.BlockedUser) { + toBlocked := func(inp []any) (res []store.BlockedUser) { res = make([]store.BlockedUser, len(inp)) for i, v := range inp { vv, ok := v.(store.BlockedUser) diff --git a/backend/app/store/engine/engine.go b/backend/app/store/engine/engine.go index c114d78b..588cd15a 100644 --- a/backend/app/store/engine/engine.go +++ b/backend/app/store/engine/engine.go @@ -24,7 +24,7 @@ type Interface interface { Count(req FindRequest) (int, error) // get count for post or user Delete(req DeleteRequest) error // Delete post(s), user, comment, user details, or everything Flag(req FlagRequest) (bool, error) // set and get flags - ListFlags(req FlagRequest) ([]interface{}, error) // get list of flagged keys, like blocked & verified user + ListFlags(req FlagRequest) ([]any, error) // get list of flagged keys, like blocked & verified user // UserDetail sets or gets single detail value, or gets all details for requested site // Returns list even for single entry request is a compromise in order to have both single detail getting and setting @@ -45,7 +45,7 @@ type FindRequest struct { Locator store.Locator `json:"locator"` // lack of URL means site operation UserID string `json:"user_id,omitempty"` // presence of UserID treated as user-related find Sort string `json:"sort,omitempty"` // sort order with +/-field syntax - Since time.Time `json:"since,omitempty"` // time limit for found results + Since time.Time `json:"since"` // time limit for found results Limit int `json:"limit,omitempty"` Skip int `json:"skip,omitempty"` } diff --git a/backend/app/store/engine/remote.go b/backend/app/store/engine/remote.go index 5a2cedec..8f1dd346 100644 --- a/backend/app/store/engine/remote.go +++ b/backend/app/store/engine/remote.go @@ -71,24 +71,24 @@ func (r *RPC) Flag(req FlagRequest) (status bool, err error) { return status, err } -func unmarshalString(data []byte) ([]interface{}, error) { +func unmarshalString(data []byte) ([]any, error) { var strings []string if err := json.Unmarshal(data, &strings); err != nil { return nil, err } - list := make([]interface{}, 0, len(strings)) + list := make([]any, 0, len(strings)) for _, w := range strings { list = append(list, w) } return list, nil } -func unmarshalBlockedUser(data []byte) ([]interface{}, error) { +func unmarshalBlockedUser(data []byte) ([]any, error) { var blockedUsers []store.BlockedUser if err := json.Unmarshal(data, &blockedUsers); err != nil { return nil, err } - list := make([]interface{}, 0, len(blockedUsers)) + list := make([]any, 0, len(blockedUsers)) for _, w := range blockedUsers { list = append(list, w) } @@ -96,7 +96,7 @@ func unmarshalBlockedUser(data []byte) ([]interface{}, error) { } // ListFlags get list of flagged keys, like blocked & verified user -func (r *RPC) ListFlags(req FlagRequest) ([]interface{}, error) { +func (r *RPC) ListFlags(req FlagRequest) ([]any, error) { resp, err := r.Call("store.list_flags", req) if err != nil { return nil, err diff --git a/backend/app/store/image/fs_store_test.go b/backend/app/store/image/fs_store_test.go index 82083e4a..a68db322 100644 --- a/backend/app/store/image/fs_store_test.go +++ b/backend/app/store/image/fs_store_test.go @@ -190,7 +190,7 @@ func TestFsStore_location(t *testing.T) { } svc := FileSystem{Location: "/tmp", Partitions: 10} - for i := 0; i < 1000; i++ { + for range 1000 { v := randomID(rand.Intn(64)) location := svc.location("/tmp", v) elems := strings.Split(location, "/") diff --git a/backend/app/store/image/image.go b/backend/app/store/image/image.go index c307be0d..fa7017dd 100644 --- a/backend/app/store/image/image.go +++ b/backend/app/store/image/image.go @@ -111,9 +111,7 @@ func (s *Service) Submit(idsFn func() []string) { s.once.Do(func() { log.Printf("[DEBUG] image submitter activated") s.submitCh = make(chan submitReq, submitQueueSize) - s.wg.Add(1) - go func() { - defer s.wg.Done() + s.wg.Go(func() { for req := range s.submitCh { // wait for EditDuration expiration with emergency pass on term for atomic.LoadInt32(&s.term) == 0 && time.Since(req.TS) <= s.EditDuration { @@ -127,7 +125,7 @@ func (s *Service) Submit(idsFn func() []string) { atomic.AddInt32(&s.submitCount, -1) } log.Printf("[INFO] image submitter terminated") - }() + }) }) atomic.AddInt32(&s.submitCount, 1) diff --git a/backend/app/store/service/restricted_words.go b/backend/app/store/service/restricted_words.go index c6400ebf..70dba67d 100644 --- a/backend/app/store/service/restricted_words.go +++ b/backend/app/store/service/restricted_words.go @@ -1,6 +1,7 @@ package service import ( + "slices" "strings" "unicode" "unicode/utf8" @@ -47,12 +48,7 @@ func (m *RestrictedWordsMatcher) Match(siteID, text string) bool { tokens := m.tokenize(text) trie := newWildcardTrie(restrictedWords...) - for _, token := range tokens { - if trie.check(token) { - return true - } - } - return false + return slices.ContainsFunc(tokens, trie.check) } func (m *RestrictedWordsMatcher) tokenize(text string) []string { diff --git a/backend/app/store/service/service.go b/backend/app/store/service/service.go index c3f0b09e..57c0390c 100644 --- a/backend/app/store/service/service.go +++ b/backend/app/store/service/service.go @@ -62,7 +62,7 @@ type UserMetaData struct { Until time.Time `json:"until"` } `json:"blocked"` Verified bool `json:"verified"` - Details engine.UserDetailEntry `json:"details,omitempty"` + Details engine.UserDetailEntry `json:"details"` } // PostMetaData keeps info about post flags @@ -676,12 +676,7 @@ func (s *DataStore) IsAdmin(siteID, userID string) bool { log.Printf("[WARN] can't get admins for %s, %v", siteID, err) return false } - for _, a := range admins { - if a == userID { - return true - } - } - return false + return slices.Contains(admins, userID) } // IsReadOnly checks if post read-only diff --git a/backend/app/store/service/service_test.go b/backend/app/store/service/service_test.go index 1b9faa89..79c16328 100644 --- a/backend/app/store/service/service_test.go +++ b/backend/app/store/service/service_test.go @@ -438,13 +438,11 @@ func TestService_VoteAggressive(t *testing.T) { // crazy vote +1 as user1 var wg sync.WaitGroup - for i := 0; i < 1000; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 1000 { + wg.Go(func() { _, _ = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: res[0].ID, UserID: "user1", Val: true}) - }() + }) } wg.Wait() res, err = b.Last("radio-t", 0, time.Time{}, store.User{ID: "user1"}) @@ -458,14 +456,12 @@ func TestService_VoteAggressive(t *testing.T) { assert.Equal(t, 0, len(res[0].VotedIPs), "vote ips hidden") // random +1/-1 result should be [0..2] - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { val := rand.Intn(2) > 0 _, _ = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: res[0].ID, UserID: "user1", Val: val}) - }() + }) } wg.Wait() res, err = b.Last("radio-t", 0, time.Time{}, store.User{}) @@ -492,14 +488,11 @@ func TestService_VoteConcurrent(t *testing.T) { // concurrent vote +1 as multiple users for the same comment var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - ii := i - go func() { - defer wg.Done() + for i := range 100 { + wg.Go(func() { _, _ = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: res[0].ID, - UserID: fmt.Sprintf("user1-%d", ii), Val: true}) - }() + UserID: fmt.Sprintf("user1-%d", i), Val: true}) + }) } wg.Wait() res, err = b.Last("radio-t", 0, time.Time{}, store.User{}) diff --git a/backend/app/store/service/title_test.go b/backend/app/store/service/title_test.go index 3e362b33..3be3de1a 100644 --- a/backend/app/store/service/title_test.go +++ b/backend/app/store/service/title_test.go @@ -61,7 +61,7 @@ func TestTitle_Get(t *testing.T) { _, err = ex.Get(ts.URL + "/bad") require.Error(t, err) - for i := 0; i < 100; i++ { + for range 100 { r, err := ex.Get(ts.URL + "/good") require.NoError(t, err) assert.Equal(t, "blah 123", r) @@ -70,9 +70,9 @@ func TestTitle_Get(t *testing.T) { } func TestTitle_GetConcurrent(t *testing.T) { - body := "" - for n := 0; n < 1000; n++ { - body += "something something blah blah\n" + var body strings.Builder + for range 1000 { + body.WriteString("something something blah blah\n") } ex := NewTitleExtractor(http.Client{Timeout: 5 * time.Second}, []string{"127.0.0.1"}) defer ex.Close() @@ -80,7 +80,7 @@ func TestTitle_GetConcurrent(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.String(), "/good") { atomic.AddInt32(&hits, 1) - _, err := fmt.Fprintf(w, "blah 123 %s%s", r.URL.String(), body) + _, err := fmt.Fprintf(w, "blah 123 %s%s", r.URL.String(), body.String()) assert.NoError(t, err) return } @@ -90,12 +90,11 @@ func TestTitle_GetConcurrent(t *testing.T) { g := syncs.NewSizedGroup(10) - for i := 0; i < 100; i++ { - ii := i + for i := range 100 { g.Go(func(_ context.Context) { - title, err := ex.Get(ts.URL + "/good/" + strconv.Itoa(ii)) + title, err := ex.Get(ts.URL + "/good/" + strconv.Itoa(i)) require.NoError(t, err) - assert.Equal(t, "blah 123 "+"/good/"+strconv.Itoa(ii), title) + assert.Equal(t, "blah 123 "+"/good/"+strconv.Itoa(i), title) }) } g.Wait() @@ -115,7 +114,7 @@ func TestTitle_GetFailed(t *testing.T) { _, err := ex.Get(ts.URL + "/bad") require.Error(t, err) - for i := 0; i < 100; i++ { + for range 100 { r, err := ex.Get(ts.URL + "/bad") require.NoError(t, err) assert.Equal(t, "", r)