From a0080acc8f6afe7c541f1b3c8db88b43bf8a6d7d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 17 Apr 2025 12:58:46 -0700 Subject: [PATCH 1/2] Fix the length --- services/feed/feed.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/feed/feed.go b/services/feed/feed.go index 38a4e25308e4f..cf607f32c0a75 100644 --- a/services/feed/feed.go +++ b/services/feed/feed.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -34,6 +35,8 @@ func GetFeeds(ctx context.Context, opts activities_model.GetFeedsOptions) (activ return activities_model.GetFeeds(ctx, opts) } +const maxActionContentLength = 65535 // this is the max length of mysql text column, sqlite, postgres and mssql have a higher limit + // notifyWatchers creates batch of actions for every watcher. // It could insert duplicate actions for a repository action, like this: // * Original action: UserID=1 (the real actor), ActUserID=1 @@ -42,6 +45,10 @@ func GetFeeds(ctx context.Context, opts activities_model.GetFeedsOptions) (activ func notifyWatchers(ctx context.Context, act *activities_model.Action, watchers []*repo_model.Watch, permCode, permIssue, permPR []bool) error { // Add feed for actioner. act.UserID = act.ActUserID + if len(act.Content) > maxActionContentLength { + act.Content = util.EllipsisDisplayString(act.Content, maxActionContentLength) + log.Warn("Action [%d, %s]'s content is too long, truncated to %d bytes", act.RepoID, act.OpType, maxActionContentLength) + } if err := db.Insert(ctx, act); err != nil { return fmt.Errorf("insert new actioner: %w", err) } From c5f735ab72a513960af4221f51b9cc5ba80e07e7 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 18 Apr 2025 09:39:39 +0800 Subject: [PATCH 2/2] fix --- services/feed/feed.go | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/services/feed/feed.go b/services/feed/feed.go index cf607f32c0a75..1dbd2e0e26f39 100644 --- a/services/feed/feed.go +++ b/services/feed/feed.go @@ -6,7 +6,7 @@ package feed import ( "context" "fmt" - "strconv" + "strings" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" @@ -14,16 +14,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/cache" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) -func userFeedCacheKey(userID int64) string { - return fmt.Sprintf("user_feed_%d", userID) -} - func GetFeedsForDashboard(ctx context.Context, opts activities_model.GetFeedsOptions) (activities_model.ActionList, int, error) { opts.DontCount = opts.RequestedTeam == nil && opts.Date == "" results, cnt, err := activities_model.GetFeeds(ctx, opts) @@ -35,20 +29,25 @@ func GetFeeds(ctx context.Context, opts activities_model.GetFeedsOptions) (activ return activities_model.GetFeeds(ctx, opts) } -const maxActionContentLength = 65535 // this is the max length of mysql text column, sqlite, postgres and mssql have a higher limit - // notifyWatchers creates batch of actions for every watcher. // It could insert duplicate actions for a repository action, like this: // * Original action: UserID=1 (the real actor), ActUserID=1 // * Organization action: UserID=100 (the repo's org), ActUserID=1 // * Watcher action: UserID=20 (a user who is watching a repo), ActUserID=1 func notifyWatchers(ctx context.Context, act *activities_model.Action, watchers []*repo_model.Watch, permCode, permIssue, permPR []bool) error { - // Add feed for actioner. - act.UserID = act.ActUserID - if len(act.Content) > maxActionContentLength { - act.Content = util.EllipsisDisplayString(act.Content, maxActionContentLength) - log.Warn("Action [%d, %s]'s content is too long, truncated to %d bytes", act.RepoID, act.OpType, maxActionContentLength) + // MySQL has TEXT length limit 65535. + // Sometimes the content is "field1|field2|field3", sometimes the content is JSON (ActionMirrorSyncPush, ActionCommitRepo, ActionPushTag, etc...) + if left, right := util.EllipsisDisplayStringX(act.Content, 65535); right != "" { + if strings.HasPrefix(act.Content, `{"`) && strings.HasSuffix(act.Content, `}`) { + // FIXME: at the moment we can do nothing if the content is JSON and it is too long + act.Content = "{}" + } else { + act.Content = left + } } + + // Add feed for actor. + act.UserID = act.ActUserID if err := db.Insert(ctx, act); err != nil { return fmt.Errorf("insert new actioner: %w", err) } @@ -83,24 +82,18 @@ func notifyWatchers(ctx context.Context, act *activities_model.Action, watchers if !permPR[i] { continue } + default: } if err := db.Insert(ctx, act); err != nil { return fmt.Errorf("insert new action: %w", err) } - - total, err := activities_model.CountUserFeeds(ctx, act.UserID) - if err != nil { - return fmt.Errorf("count user feeds: %w", err) - } - - _ = cache.GetCache().Put(userFeedCacheKey(act.UserID), strconv.FormatInt(total, 10), setting.CacheService.TTLSeconds()) } return nil } -// NotifyWatchersActions creates batch of actions for every watcher. +// NotifyWatchers creates batch of actions for every watcher. func NotifyWatchers(ctx context.Context, acts ...*activities_model.Action) error { return db.WithTx(ctx, func(ctx context.Context) error { if len(acts) == 0 {