snapshot of https://github.com/go-gitea/gitea.git (main, 2026-09-15; blobs > 131072B omitted)
Some checks failed
cache-seeder / prune (push) Has been skipped
cache-seeder / frontend (push) Failing after 3s
cache-seeder / python (push) Failing after 3s
cache-seeder / gobuild (push) Failing after 4s
cache-seeder / lint (bindata, lint-backend) (push) Failing after 3s
giteabot backport / giteabot (push) Has been skipped
giteabot / giteabot (push) Has been skipped
cache-prune / prune (push) Has been skipped
release-nightly-snapcraft / build-and-publish (ubuntu-24.04) (push) Has been cancelled
release-nightly-snapcraft / build-and-publish (ubuntu-24.04-arm) (push) Has been cancelled
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
cron-renovate / cron-renovate (push) Has been skipped
Some checks failed
cache-seeder / prune (push) Has been skipped
cache-seeder / frontend (push) Failing after 3s
cache-seeder / python (push) Failing after 3s
cache-seeder / gobuild (push) Failing after 4s
cache-seeder / lint (bindata, lint-backend) (push) Failing after 3s
giteabot backport / giteabot (push) Has been skipped
giteabot / giteabot (push) Has been skipped
cache-prune / prune (push) Has been skipped
release-nightly-snapcraft / build-and-publish (ubuntu-24.04) (push) Has been cancelled
release-nightly-snapcraft / build-and-publish (ubuntu-24.04-arm) (push) Has been cancelled
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
cron-renovate / cron-renovate (push) Has been skipped
This commit is contained in:
164
services/feed/feed.go
Normal file
164
services/feed/feed.go
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package feed
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
activities_model "gitea.dev/models/activities"
|
||||
"gitea.dev/models/db"
|
||||
access_model "gitea.dev/models/perm/access"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
"gitea.dev/models/unit"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
func GetFeedsForDashboard(ctx context.Context, opts activities_model.GetFeedsOptions) (activities_model.ActionList, int64, error) {
|
||||
opts.DontCount = opts.RequestedTeam == nil && opts.Date == ""
|
||||
results, cnt, err := activities_model.GetFeeds(ctx, opts)
|
||||
return results, util.Iif(opts.DontCount, -1, cnt), err
|
||||
}
|
||||
|
||||
// GetFeeds returns actions according to the provided options
|
||||
func GetFeeds(ctx context.Context, opts activities_model.GetFeedsOptions) (activities_model.ActionList, int64, error) {
|
||||
return activities_model.GetFeeds(ctx, opts)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Add feed for organization
|
||||
if act.Repo.Owner.IsOrganization() && act.ActUserID != act.Repo.Owner.ID {
|
||||
act.ID = 0
|
||||
act.UserID = act.Repo.Owner.ID
|
||||
if err := db.Insert(ctx, act); err != nil {
|
||||
return fmt.Errorf("insert new actioner: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, watcher := range watchers {
|
||||
if act.ActUserID == watcher.UserID {
|
||||
continue
|
||||
}
|
||||
act.ID = 0
|
||||
act.UserID = watcher.UserID
|
||||
act.Repo.Units = nil
|
||||
|
||||
var allowed bool
|
||||
switch act.OpType {
|
||||
case activities_model.ActionCommitRepo, activities_model.ActionPushTag, activities_model.ActionDeleteTag, activities_model.ActionDeleteBranch:
|
||||
allowed = permCode[i] && watcher.IsWatchingAll()
|
||||
case activities_model.ActionPublishRelease:
|
||||
allowed = permCode[i] && watcher.IncludeReleases
|
||||
case activities_model.ActionCreateIssue, activities_model.ActionCommentIssue, activities_model.ActionCloseIssue, activities_model.ActionReopenIssue:
|
||||
allowed = permIssue[i] && watcher.IncludeIssues
|
||||
case activities_model.ActionCreatePullRequest, activities_model.ActionCommentPull, activities_model.ActionMergePullRequest, activities_model.ActionClosePullRequest,
|
||||
activities_model.ActionReopenPullRequest, activities_model.ActionAutoMergePullRequest, activities_model.ActionApprovePullRequest,
|
||||
activities_model.ActionRejectPullRequest, activities_model.ActionPullReviewDismissed, activities_model.ActionPullRequestReadyForReview:
|
||||
allowed = permPR[i] && watcher.IncludePullRequests
|
||||
default:
|
||||
allowed = watcher.IsWatchingAll() // repository events have no watch option of their own
|
||||
}
|
||||
if !allowed {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := db.Insert(ctx, act); err != nil {
|
||||
return fmt.Errorf("insert new action: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil
|
||||
}
|
||||
|
||||
repoID := acts[0].RepoID
|
||||
if repoID == 0 {
|
||||
setting.PanicInDevOrTesting("action should belong to a repo")
|
||||
return nil
|
||||
}
|
||||
if err := acts[0].LoadRepo(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
repo := acts[0].Repo
|
||||
if err := repo.LoadOwner(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
actUserID := acts[0].ActUserID
|
||||
|
||||
// Add feeds for user self and all watchers.
|
||||
watchers, err := repo_model.GetWatchers(ctx, repoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get watchers: %w", err)
|
||||
}
|
||||
permCode := make([]bool, len(watchers))
|
||||
permIssue := make([]bool, len(watchers))
|
||||
permPR := make([]bool, len(watchers))
|
||||
for i, watcher := range watchers {
|
||||
user, err := user_model.GetUserByID(ctx, watcher.UserID)
|
||||
if err != nil {
|
||||
permCode[i] = false
|
||||
permIssue[i] = false
|
||||
permPR[i] = false
|
||||
continue
|
||||
}
|
||||
perm, err := access_model.GetIndividualUserRepoPermission(ctx, repo, user)
|
||||
if err != nil {
|
||||
permCode[i] = false
|
||||
permIssue[i] = false
|
||||
permPR[i] = false
|
||||
continue
|
||||
}
|
||||
permCode[i] = perm.CanRead(unit.TypeCode)
|
||||
permIssue[i] = perm.CanRead(unit.TypeIssues)
|
||||
permPR[i] = perm.CanRead(unit.TypePullRequests)
|
||||
}
|
||||
|
||||
for _, act := range acts {
|
||||
if act.RepoID != repoID {
|
||||
setting.PanicInDevOrTesting("action should belong to the same repo, expected[%d], got[%d] ", repoID, act.RepoID)
|
||||
}
|
||||
if act.ActUserID != actUserID {
|
||||
setting.PanicInDevOrTesting("action should have the same actor, expected[%d], got[%d] ", actUserID, act.ActUserID)
|
||||
}
|
||||
|
||||
act.Repo = repo
|
||||
if err := notifyWatchers(ctx, act, watchers, permCode, permIssue, permPR); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user