Skip to content

Commit 17d62fa

Browse files
author
Loïc Dachary
committed
Revert "some refactor about code comments(go-gitea#20821) (go-gitea#22707)"
This reverts commit 1d191f9. Refs: https://codeberg.org/forgejo/forgejo/issues/395
1 parent cb7ea00 commit 17d62fa

File tree

7 files changed

+188
-260
lines changed

7 files changed

+188
-260
lines changed

models/db/list_options.go

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55
package db
66

77
import (
8-
"context"
9-
108
"code.gitea.io/gitea/modules/setting"
119

12-
"xorm.io/builder"
1310
"xorm.io/xorm"
1411
)
1512

@@ -22,7 +19,6 @@ const (
2219
type Paginator interface {
2320
GetSkipTake() (skip, take int)
2421
GetStartEnd() (start, end int)
25-
IsListAll() bool
2622
}
2723

2824
// GetPaginatedSession creates a paginated database session
@@ -49,12 +45,9 @@ func SetEnginePagination(e Engine, p Paginator) Engine {
4945
// ListOptions options to paginate results
5046
type ListOptions struct {
5147
PageSize int
52-
Page int // start from 1
53-
ListAll bool // if true, then PageSize and Page will not be taken
48+
Page int // start from 1
5449
}
5550

56-
var _ Paginator = &ListOptions{}
57-
5851
// GetSkipTake returns the skip and take values
5952
func (opts *ListOptions) GetSkipTake() (skip, take int) {
6053
opts.SetDefaultValues()
@@ -68,11 +61,6 @@ func (opts *ListOptions) GetStartEnd() (start, end int) {
6861
return start, end
6962
}
7063

71-
// IsListAll indicates PageSize and Page will be ignored
72-
func (opts *ListOptions) IsListAll() bool {
73-
return opts.ListAll
74-
}
75-
7664
// SetDefaultValues sets default values
7765
func (opts *ListOptions) SetDefaultValues() {
7866
if opts.PageSize <= 0 {
@@ -92,8 +80,6 @@ type AbsoluteListOptions struct {
9280
take int
9381
}
9482

95-
var _ Paginator = &AbsoluteListOptions{}
96-
9783
// NewAbsoluteListOptions creates a list option with applied limits
9884
func NewAbsoluteListOptions(skip, take int) *AbsoluteListOptions {
9985
if skip < 0 {
@@ -108,11 +94,6 @@ func NewAbsoluteListOptions(skip, take int) *AbsoluteListOptions {
10894
return &AbsoluteListOptions{skip, take}
10995
}
11096

111-
// IsListAll will always return false
112-
func (opts *AbsoluteListOptions) IsListAll() bool {
113-
return false
114-
}
115-
11697
// GetSkipTake returns the skip and take values
11798
func (opts *AbsoluteListOptions) GetSkipTake() (skip, take int) {
11899
return opts.skip, opts.take
@@ -122,32 +103,3 @@ func (opts *AbsoluteListOptions) GetSkipTake() (skip, take int) {
122103
func (opts *AbsoluteListOptions) GetStartEnd() (start, end int) {
123104
return opts.skip, opts.skip + opts.take
124105
}
125-
126-
// FindOptions represents a find options
127-
type FindOptions interface {
128-
Paginator
129-
ToConds() builder.Cond
130-
}
131-
132-
// Find represents a common find function which accept an options interface
133-
func Find[T any](ctx context.Context, opts FindOptions, objects *[]T) error {
134-
sess := GetEngine(ctx).Where(opts.ToConds())
135-
if !opts.IsListAll() {
136-
sess.Limit(opts.GetSkipTake())
137-
}
138-
return sess.Find(&objects)
139-
}
140-
141-
// Count represents a common count function which accept an options interface
142-
func Count[T any](ctx context.Context, opts FindOptions, object T) (int64, error) {
143-
return GetEngine(ctx).Where(opts.ToConds()).Count(object)
144-
}
145-
146-
// FindAndCount represents a common findandcount function which accept an options interface
147-
func FindAndCount[T any](ctx context.Context, opts FindOptions, objects *[]T) (int64, error) {
148-
sess := GetEngine(ctx).Where(opts.ToConds())
149-
if !opts.IsListAll() {
150-
sess.Limit(opts.GetSkipTake())
151-
}
152-
return sess.FindAndCount(&objects)
153-
}

models/issues/comment.go

Lines changed: 156 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ package issues
99
import (
1010
"context"
1111
"fmt"
12+
"regexp"
1213
"strconv"
14+
"strings"
1315
"unicode/utf8"
1416

1517
"code.gitea.io/gitea/models/db"
@@ -21,6 +23,8 @@ import (
2123
"code.gitea.io/gitea/modules/git"
2224
"code.gitea.io/gitea/modules/json"
2325
"code.gitea.io/gitea/modules/log"
26+
"code.gitea.io/gitea/modules/markup"
27+
"code.gitea.io/gitea/modules/markup/markdown"
2428
"code.gitea.io/gitea/modules/references"
2529
"code.gitea.io/gitea/modules/structs"
2630
"code.gitea.io/gitea/modules/timeutil"
@@ -693,6 +697,31 @@ func (c *Comment) LoadReview() error {
693697
return c.loadReview(db.DefaultContext)
694698
}
695699

700+
var notEnoughLines = regexp.MustCompile(`fatal: file .* has only \d+ lines?`)
701+
702+
func (c *Comment) checkInvalidation(doer *user_model.User, repo *git.Repository, branch string) error {
703+
// FIXME differentiate between previous and proposed line
704+
commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine()))
705+
if err != nil && (strings.Contains(err.Error(), "fatal: no such path") || notEnoughLines.MatchString(err.Error())) {
706+
c.Invalidated = true
707+
return UpdateComment(c, doer)
708+
}
709+
if err != nil {
710+
return err
711+
}
712+
if c.CommitSHA != "" && c.CommitSHA != commit.ID.String() {
713+
c.Invalidated = true
714+
return UpdateComment(c, doer)
715+
}
716+
return nil
717+
}
718+
719+
// CheckInvalidation checks if the line of code comment got changed by another commit.
720+
// If the line got changed the comment is going to be invalidated.
721+
func (c *Comment) CheckInvalidation(repo *git.Repository, doer *user_model.User, branch string) error {
722+
return c.checkInvalidation(doer, repo, branch)
723+
}
724+
696725
// DiffSide returns "previous" if Comment.Line is a LOC of the previous changes and "proposed" if it is a LOC of the proposed changes.
697726
func (c *Comment) DiffSide() string {
698727
if c.Line < 0 {
@@ -1036,28 +1065,23 @@ func GetCommentByID(ctx context.Context, id int64) (*Comment, error) {
10361065
// FindCommentsOptions describes the conditions to Find comments
10371066
type FindCommentsOptions struct {
10381067
db.ListOptions
1039-
RepoID int64
1040-
IssueID int64
1041-
ReviewID int64
1042-
Since int64
1043-
Before int64
1044-
Line int64
1045-
TreePath string
1046-
Type CommentType
1047-
IssueIDs []int64
1048-
Invalidated util.OptionalBool
1049-
}
1050-
1051-
// ToConds implements FindOptions interface
1052-
func (opts *FindCommentsOptions) ToConds() builder.Cond {
1068+
RepoID int64
1069+
IssueID int64
1070+
ReviewID int64
1071+
Since int64
1072+
Before int64
1073+
Line int64
1074+
TreePath string
1075+
Type CommentType
1076+
}
1077+
1078+
func (opts *FindCommentsOptions) toConds() builder.Cond {
10531079
cond := builder.NewCond()
10541080
if opts.RepoID > 0 {
10551081
cond = cond.And(builder.Eq{"issue.repo_id": opts.RepoID})
10561082
}
10571083
if opts.IssueID > 0 {
10581084
cond = cond.And(builder.Eq{"comment.issue_id": opts.IssueID})
1059-
} else if len(opts.IssueIDs) > 0 {
1060-
cond = cond.And(builder.In("comment.issue_id", opts.IssueIDs))
10611085
}
10621086
if opts.ReviewID > 0 {
10631087
cond = cond.And(builder.Eq{"comment.review_id": opts.ReviewID})
@@ -1077,16 +1101,13 @@ func (opts *FindCommentsOptions) ToConds() builder.Cond {
10771101
if len(opts.TreePath) > 0 {
10781102
cond = cond.And(builder.Eq{"comment.tree_path": opts.TreePath})
10791103
}
1080-
if !opts.Invalidated.IsNone() {
1081-
cond = cond.And(builder.Eq{"comment.invalidated": opts.Invalidated.IsTrue()})
1082-
}
10831104
return cond
10841105
}
10851106

10861107
// FindComments returns all comments according options
10871108
func FindComments(ctx context.Context, opts *FindCommentsOptions) ([]*Comment, error) {
10881109
comments := make([]*Comment, 0, 10)
1089-
sess := db.GetEngine(ctx).Where(opts.ToConds())
1110+
sess := db.GetEngine(ctx).Where(opts.toConds())
10901111
if opts.RepoID > 0 {
10911112
sess.Join("INNER", "issue", "issue.id = comment.issue_id")
10921113
}
@@ -1105,19 +1126,13 @@ func FindComments(ctx context.Context, opts *FindCommentsOptions) ([]*Comment, e
11051126

11061127
// CountComments count all comments according options by ignoring pagination
11071128
func CountComments(opts *FindCommentsOptions) (int64, error) {
1108-
sess := db.GetEngine(db.DefaultContext).Where(opts.ToConds())
1129+
sess := db.GetEngine(db.DefaultContext).Where(opts.toConds())
11091130
if opts.RepoID > 0 {
11101131
sess.Join("INNER", "issue", "issue.id = comment.issue_id")
11111132
}
11121133
return sess.Count(&Comment{})
11131134
}
11141135

1115-
// UpdateCommentInvalidate updates comment invalidated column
1116-
func UpdateCommentInvalidate(ctx context.Context, c *Comment) error {
1117-
_, err := db.GetEngine(ctx).ID(c.ID).Cols("invalidated").Update(c)
1118-
return err
1119-
}
1120-
11211136
// UpdateComment updates information of comment.
11221137
func UpdateComment(c *Comment, doer *user_model.User) error {
11231138
ctx, committer, err := db.TxContext()
@@ -1176,6 +1191,120 @@ func DeleteComment(ctx context.Context, comment *Comment) error {
11761191
return DeleteReaction(ctx, &ReactionOptions{CommentID: comment.ID})
11771192
}
11781193

1194+
// CodeComments represents comments on code by using this structure: FILENAME -> LINE (+ == proposed; - == previous) -> COMMENTS
1195+
type CodeComments map[string]map[int64][]*Comment
1196+
1197+
// FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line
1198+
func FetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User) (CodeComments, error) {
1199+
return fetchCodeCommentsByReview(ctx, issue, currentUser, nil)
1200+
}
1201+
1202+
func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *user_model.User, review *Review) (CodeComments, error) {
1203+
pathToLineToComment := make(CodeComments)
1204+
if review == nil {
1205+
review = &Review{ID: 0}
1206+
}
1207+
opts := FindCommentsOptions{
1208+
Type: CommentTypeCode,
1209+
IssueID: issue.ID,
1210+
ReviewID: review.ID,
1211+
}
1212+
1213+
comments, err := findCodeComments(ctx, opts, issue, currentUser, review)
1214+
if err != nil {
1215+
return nil, err
1216+
}
1217+
1218+
for _, comment := range comments {
1219+
if pathToLineToComment[comment.TreePath] == nil {
1220+
pathToLineToComment[comment.TreePath] = make(map[int64][]*Comment)
1221+
}
1222+
pathToLineToComment[comment.TreePath][comment.Line] = append(pathToLineToComment[comment.TreePath][comment.Line], comment)
1223+
}
1224+
return pathToLineToComment, nil
1225+
}
1226+
1227+
func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issue, currentUser *user_model.User, review *Review) ([]*Comment, error) {
1228+
var comments []*Comment
1229+
if review == nil {
1230+
review = &Review{ID: 0}
1231+
}
1232+
conds := opts.toConds()
1233+
if review.ID == 0 {
1234+
conds = conds.And(builder.Eq{"invalidated": false})
1235+
}
1236+
e := db.GetEngine(ctx)
1237+
if err := e.Where(conds).
1238+
Asc("comment.created_unix").
1239+
Asc("comment.id").
1240+
Find(&comments); err != nil {
1241+
return nil, err
1242+
}
1243+
1244+
if err := issue.LoadRepo(ctx); err != nil {
1245+
return nil, err
1246+
}
1247+
1248+
if err := CommentList(comments).loadPosters(ctx); err != nil {
1249+
return nil, err
1250+
}
1251+
1252+
// Find all reviews by ReviewID
1253+
reviews := make(map[int64]*Review)
1254+
ids := make([]int64, 0, len(comments))
1255+
for _, comment := range comments {
1256+
if comment.ReviewID != 0 {
1257+
ids = append(ids, comment.ReviewID)
1258+
}
1259+
}
1260+
if err := e.In("id", ids).Find(&reviews); err != nil {
1261+
return nil, err
1262+
}
1263+
1264+
n := 0
1265+
for _, comment := range comments {
1266+
if re, ok := reviews[comment.ReviewID]; ok && re != nil {
1267+
// If the review is pending only the author can see the comments (except if the review is set)
1268+
if review.ID == 0 && re.Type == ReviewTypePending &&
1269+
(currentUser == nil || currentUser.ID != re.ReviewerID) {
1270+
continue
1271+
}
1272+
comment.Review = re
1273+
}
1274+
comments[n] = comment
1275+
n++
1276+
1277+
if err := comment.LoadResolveDoer(); err != nil {
1278+
return nil, err
1279+
}
1280+
1281+
if err := comment.LoadReactions(issue.Repo); err != nil {
1282+
return nil, err
1283+
}
1284+
1285+
var err error
1286+
if comment.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
1287+
Ctx: ctx,
1288+
URLPrefix: issue.Repo.Link(),
1289+
Metas: issue.Repo.ComposeMetas(),
1290+
}, comment.Content); err != nil {
1291+
return nil, err
1292+
}
1293+
}
1294+
return comments[:n], nil
1295+
}
1296+
1297+
// FetchCodeCommentsByLine fetches the code comments for a given treePath and line number
1298+
func FetchCodeCommentsByLine(ctx context.Context, issue *Issue, currentUser *user_model.User, treePath string, line int64) ([]*Comment, error) {
1299+
opts := FindCommentsOptions{
1300+
Type: CommentTypeCode,
1301+
IssueID: issue.ID,
1302+
TreePath: treePath,
1303+
Line: line,
1304+
}
1305+
return findCodeComments(ctx, opts, issue, currentUser, nil)
1306+
}
1307+
11791308
// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id
11801309
func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
11811310
_, err := db.GetEngine(db.DefaultContext).Table("comment").

0 commit comments

Comments
 (0)