mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 02:24:57 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2024 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package feed
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| 
 | |
| 	activities_model "code.gitea.io/gitea/models/activities"
 | |
| 	"code.gitea.io/gitea/models/db"
 | |
| 	access_model "code.gitea.io/gitea/models/perm/access"
 | |
| 	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/setting"
 | |
| 	"code.gitea.io/gitea/modules/util"
 | |
| )
 | |
| 
 | |
| 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)
 | |
| 	return results, util.Iif(opts.DontCount, -1, int(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
 | |
| 
 | |
| 		switch act.OpType {
 | |
| 		case activities_model.ActionCommitRepo, activities_model.ActionPushTag, activities_model.ActionDeleteTag, activities_model.ActionPublishRelease, activities_model.ActionDeleteBranch:
 | |
| 			if !permCode[i] {
 | |
| 				continue
 | |
| 			}
 | |
| 		case activities_model.ActionCreateIssue, activities_model.ActionCommentIssue, activities_model.ActionCloseIssue, activities_model.ActionReopenIssue:
 | |
| 			if !permIssue[i] {
 | |
| 				continue
 | |
| 			}
 | |
| 		case activities_model.ActionCreatePullRequest, activities_model.ActionCommentPull, activities_model.ActionMergePullRequest, activities_model.ActionClosePullRequest, activities_model.ActionReopenPullRequest, activities_model.ActionAutoMergePullRequest:
 | |
| 			if !permPR[i] {
 | |
| 				continue
 | |
| 			}
 | |
| 		default:
 | |
| 		}
 | |
| 
 | |
| 		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.GetUserRepoPermission(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
 | |
| 	})
 | |
| }
 |