mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Allow to mark files in a PR as viewed (#19007)
Users can now mark files in PRs as viewed, resulting in them not being shown again by default when they reopen the PR again.
This commit is contained in:
		| @@ -22,6 +22,7 @@ import ( | ||||
|  | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/models/db" | ||||
| 	pull_model "code.gitea.io/gitea/models/pull" | ||||
| 	user_model "code.gitea.io/gitea/models/user" | ||||
| 	"code.gitea.io/gitea/modules/analyze" | ||||
| 	"code.gitea.io/gitea/modules/charset" | ||||
| @@ -602,25 +603,27 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) Dif | ||||
|  | ||||
| // DiffFile represents a file diff. | ||||
| type DiffFile struct { | ||||
| 	Name                    string | ||||
| 	OldName                 string | ||||
| 	Index                   int | ||||
| 	Addition, Deletion      int | ||||
| 	Type                    DiffFileType | ||||
| 	IsCreated               bool | ||||
| 	IsDeleted               bool | ||||
| 	IsBin                   bool | ||||
| 	IsLFSFile               bool | ||||
| 	IsRenamed               bool | ||||
| 	IsAmbiguous             bool | ||||
| 	IsSubmodule             bool | ||||
| 	Sections                []*DiffSection | ||||
| 	IsIncomplete            bool | ||||
| 	IsIncompleteLineTooLong bool | ||||
| 	IsProtected             bool | ||||
| 	IsGenerated             bool | ||||
| 	IsVendored              bool | ||||
| 	Language                string | ||||
| 	Name                      string | ||||
| 	OldName                   string | ||||
| 	Index                     int | ||||
| 	Addition, Deletion        int | ||||
| 	Type                      DiffFileType | ||||
| 	IsCreated                 bool | ||||
| 	IsDeleted                 bool | ||||
| 	IsBin                     bool | ||||
| 	IsLFSFile                 bool | ||||
| 	IsRenamed                 bool | ||||
| 	IsAmbiguous               bool | ||||
| 	IsSubmodule               bool | ||||
| 	Sections                  []*DiffSection | ||||
| 	IsIncomplete              bool | ||||
| 	IsIncompleteLineTooLong   bool | ||||
| 	IsProtected               bool | ||||
| 	IsGenerated               bool | ||||
| 	IsVendored                bool | ||||
| 	IsViewed                  bool // User specific | ||||
| 	HasChangedSinceLastReview bool // User specific | ||||
| 	Language                  string | ||||
| } | ||||
|  | ||||
| // GetType returns type of diff file. | ||||
| @@ -663,6 +666,18 @@ func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, | ||||
| 	return tailSection | ||||
| } | ||||
|  | ||||
| // GetDiffFileName returns the name of the diff file, or its old name in case it was deleted | ||||
| func (diffFile *DiffFile) GetDiffFileName() string { | ||||
| 	if diffFile.Name == "" { | ||||
| 		return diffFile.OldName | ||||
| 	} | ||||
| 	return diffFile.Name | ||||
| } | ||||
|  | ||||
| func (diffFile *DiffFile) ShouldBeHidden() bool { | ||||
| 	return diffFile.IsGenerated || diffFile.IsViewed | ||||
| } | ||||
|  | ||||
| func getCommitFileLineCount(commit *git.Commit, filePath string) int { | ||||
| 	blob, err := commit.GetBlobByPath(filePath) | ||||
| 	if err != nil { | ||||
| @@ -677,10 +692,12 @@ func getCommitFileLineCount(commit *git.Commit, filePath string) int { | ||||
|  | ||||
| // Diff represents a difference between two git trees. | ||||
| type Diff struct { | ||||
| 	Start, End                             string | ||||
| 	NumFiles, TotalAddition, TotalDeletion int | ||||
| 	Files                                  []*DiffFile | ||||
| 	IsIncomplete                           bool | ||||
| 	Start, End                   string | ||||
| 	NumFiles                     int | ||||
| 	TotalAddition, TotalDeletion int | ||||
| 	Files                        []*DiffFile | ||||
| 	IsIncomplete                 bool | ||||
| 	NumViewedFiles               int // user-specific | ||||
| } | ||||
|  | ||||
| // LoadComments loads comments into each line | ||||
| @@ -1497,6 +1514,70 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff | ||||
| 	return diff, nil | ||||
| } | ||||
|  | ||||
| // SyncAndGetUserSpecificDiff is like GetDiff, except that user specific data such as which files the given user has already viewed on the given PR will also be set | ||||
| // Additionally, the database asynchronously is updated if files have changed since the last review | ||||
| func SyncAndGetUserSpecificDiff(ctx context.Context, userID int64, pull *models.PullRequest, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) { | ||||
| 	diff, err := GetDiff(gitRepo, opts, files...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	review, err := pull_model.GetNewestReviewState(ctx, userID, pull.ID) | ||||
| 	if err != nil || review == nil || review.UpdatedFiles == nil { | ||||
| 		return diff, err | ||||
| 	} | ||||
|  | ||||
| 	latestCommit := opts.AfterCommitID | ||||
| 	if latestCommit == "" { | ||||
| 		latestCommit = pull.HeadBranch // opts.AfterCommitID is preferred because it handles PRs from forks correctly and the branch name doesn't | ||||
| 	} | ||||
|  | ||||
| 	changedFiles, err := gitRepo.GetFilesChangedBetween(review.CommitSHA, latestCommit) | ||||
| 	if err != nil { | ||||
| 		return diff, err | ||||
| 	} | ||||
|  | ||||
| 	filesChangedSinceLastDiff := make(map[string]pull_model.ViewedState) | ||||
| outer: | ||||
| 	for _, diffFile := range diff.Files { | ||||
| 		fileViewedState := review.UpdatedFiles[diffFile.GetDiffFileName()] | ||||
|  | ||||
| 		// Check whether it was previously detected that the file has changed since the last review | ||||
| 		if fileViewedState == pull_model.HasChanged { | ||||
| 			diffFile.HasChangedSinceLastReview = true | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		filename := diffFile.GetDiffFileName() | ||||
|  | ||||
| 		// Check explicitly whether the file has changed since the last review | ||||
| 		for _, changedFile := range changedFiles { | ||||
| 			diffFile.HasChangedSinceLastReview = filename == changedFile | ||||
| 			if diffFile.HasChangedSinceLastReview { | ||||
| 				filesChangedSinceLastDiff[filename] = pull_model.HasChanged | ||||
| 				continue outer // We don't want to check if the file is viewed here as that would fold the file, which is in this case unwanted | ||||
| 			} | ||||
| 		} | ||||
| 		// Check whether the file has already been viewed | ||||
| 		if fileViewedState == pull_model.Viewed { | ||||
| 			diffFile.IsViewed = true | ||||
| 			diff.NumViewedFiles++ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Explicitly store files that have changed in the database, if any is present at all. | ||||
| 	// This has the benefit that the "Has Changed" attribute will be present as long as the user does not explicitly mark this file as viewed, so it will even survive a page reload after marking another file as viewed. | ||||
| 	// On the other hand, this means that even if a commit reverting an unseen change is committed, the file will still be seen as changed. | ||||
| 	if len(filesChangedSinceLastDiff) > 0 { | ||||
| 		err := pull_model.UpdateReviewState(ctx, review.UserID, review.PullID, review.CommitSHA, filesChangedSinceLastDiff) | ||||
| 		if err != nil { | ||||
| 			log.Warn("Could not update review for user %d, pull %d, commit %s and the changed files %v: %v", review.UserID, review.PullID, review.CommitSHA, filesChangedSinceLastDiff, err) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return diff, err | ||||
| } | ||||
|  | ||||
| // CommentAsDiff returns c.Patch as *Diff | ||||
| func CommentAsDiff(c *models.Comment) (*Diff, error) { | ||||
| 	diff, err := ParsePatch(setting.Git.MaxGitDiffLines, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user