From 5f5212ca60923e160e77d2a429358ef45d855ad2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 22 Feb 2024 12:17:38 +0800 Subject: [PATCH 01/13] Add issue comment when moving issues from one column to another of the project --- models/issues/comment.go | 78 ++++++++++++------- models/issues/issue_list.go | 1 + models/migrations/migrations.go | 2 + models/migrations/v1_22/v287.go | 1 - models/migrations/v1_23/v300.go | 22 ++++++ options/locale/locale_en-US.ini | 1 + routers/web/org/projects.go | 3 +- routers/web/repo/issue.go | 5 ++ routers/web/repo/projects.go | 3 +- services/projects/issue.go | 76 ++++++++++++++++++ .../repo/issue/view_content/comments.tmpl | 16 ++++ 11 files changed, 177 insertions(+), 31 deletions(-) create mode 100644 models/migrations/v1_23/v300.go create mode 100644 services/projects/issue.go diff --git a/models/issues/comment.go b/models/issues/comment.go index c6c5dc24321d1..d6e5504d72091 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -222,6 +222,13 @@ func (r RoleInRepo) LocaleHelper(lang translation.Locale) string { return lang.TrString("repo.issues.role." + string(r) + "_helper") } +// CommentMetaData stores metadata for a comment, these data will not be changed once inserted into database +type CommentMetaData struct { + ProjectColumnID int64 `json:"project_column_id"` + ProjectColumnTitle string `json:"project_column_name"` + ProjectTitle string `json:"project_name"` +} + // Comment represents a comment in commit and issue page. type Comment struct { ID int64 `xorm:"pk autoincr"` @@ -295,6 +302,8 @@ type Comment struct { RefAction references.XRefAction `xorm:"SMALLINT"` // What happens if RefIssueID resolves RefIsPull bool + CommentMetaData *CommentMetaData `xorm:"JSON TEXT"` // put all non-index metadata in a single field + RefRepo *repo_model.Repository `xorm:"-"` RefIssue *Issue `xorm:"-"` RefComment *Comment `xorm:"-"` @@ -797,6 +806,15 @@ func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, LabelID = opts.Label.ID } + var commentMetaData *CommentMetaData + if opts.ProjectColumnID > 0 { + commentMetaData = &CommentMetaData{ + ProjectColumnID: opts.ProjectColumnID, + ProjectColumnTitle: opts.ProjectColumnTitle, + ProjectTitle: opts.ProjectColumnTitle, + } + } + comment := &Comment{ Type: opts.Type, PosterID: opts.Doer.ID, @@ -830,6 +848,7 @@ func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, RefIsPull: opts.RefIsPull, IsForcePush: opts.IsForcePush, Invalidated: opts.Invalidated, + CommentMetaData: commentMetaData, } if _, err = e.Insert(comment); err != nil { return nil, err @@ -982,34 +1001,37 @@ type CreateCommentOptions struct { Issue *Issue Label *Label - DependentIssueID int64 - OldMilestoneID int64 - MilestoneID int64 - OldProjectID int64 - ProjectID int64 - TimeID int64 - AssigneeID int64 - AssigneeTeamID int64 - RemovedAssignee bool - OldTitle string - NewTitle string - OldRef string - NewRef string - CommitID int64 - CommitSHA string - Patch string - LineNum int64 - TreePath string - ReviewID int64 - Content string - Attachments []string // UUIDs of attachments - RefRepoID int64 - RefIssueID int64 - RefCommentID int64 - RefAction references.XRefAction - RefIsPull bool - IsForcePush bool - Invalidated bool + DependentIssueID int64 + OldMilestoneID int64 + MilestoneID int64 + OldProjectID int64 + ProjectID int64 + ProjectTitle string + ProjectColumnID int64 + ProjectColumnTitle string + TimeID int64 + AssigneeID int64 + AssigneeTeamID int64 + RemovedAssignee bool + OldTitle string + NewTitle string + OldRef string + NewRef string + CommitID int64 + CommitSHA string + Patch string + LineNum int64 + TreePath string + ReviewID int64 + Content string + Attachments []string // UUIDs of attachments + RefRepoID int64 + RefIssueID int64 + RefCommentID int64 + RefAction references.XRefAction + RefIsPull bool + IsForcePush bool + Invalidated bool } // GetCommentByID returns the comment by given ID. diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index f8ee271a6bbf5..9c0d3bb1c9ec7 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -434,6 +434,7 @@ func (issues IssueList) loadComments(ctx context.Context, cond builder.Cond) (er Join("INNER", "issue", "issue.id = comment.issue_id"). In("issue.id", issuesIDs[:limit]). Where(cond). + NoAutoCondition(). Rows(new(Comment)) if err != nil { return err diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 08882fb1195cc..353dd5b927473 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -591,6 +591,8 @@ var migrations = []Migration{ // v299 -> v300 NewMigration("Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment), + // v300 -> v301 + NewMigration("Add metadata column for comment table", v1_23.AddCommentMetaDataColumn), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_22/v287.go b/models/migrations/v1_22/v287.go index c8b1593286945..14bcaeada8724 100644 --- a/models/migrations/v1_22/v287.go +++ b/models/migrations/v1_22/v287.go @@ -1,6 +1,5 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT - package v1_22 //nolint import ( diff --git a/models/migrations/v1_23/v300.go b/models/migrations/v1_23/v300.go new file mode 100644 index 0000000000000..acb4e32c41231 --- /dev/null +++ b/models/migrations/v1_23/v300.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT +package v1_23 //nolint + +import ( + "xorm.io/xorm" +) + +// CommentMetaData stores metadata for a comment, these data will not be changed once inserted into database +type CommentMetaData struct { + ProjectColumnID int64 `json:"project_column_id"` + ProjectColumnName string `json:"project_column_name"` + ProjectName string `json:"project_name"` +} + +func AddCommentMetaDataColumn(x *xorm.Engine) error { + type Comment struct { + CommentMetaData CommentMetaData `xorm:"JSON TEXT"` // put all non-index metadata in a single field + } + + return x.Sync(new(Comment)) +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 772b11c2ba65c..9077fe8041bad 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1470,6 +1470,7 @@ issues.remove_labels = removed the %s labels %s issues.add_remove_labels = added %s and removed %s labels %s issues.add_milestone_at = `added this to the %s milestone %s` issues.add_project_at = `added this to the %s project %s` +issues.move_to_column_of_project = `moved this to %s in %s on %s` issues.change_milestone_at = `modified the milestone from %s to %s %s` issues.change_project_at = `modified the project from %s to %s %s` issues.remove_milestone_at = `removed this from the %s milestone %s` diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 8fb8f2540f339..75ceed459ffa1 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -23,6 +23,7 @@ import ( shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" + project_service "code.gitea.io/gitea/services/projects" ) const ( @@ -600,7 +601,7 @@ func MoveIssues(ctx *context.Context) { } } - if err = project_model.MoveIssuesOnProjectColumn(ctx, column, sortedIssueIDs); err != nil { + if err = project_service.MoveIssuesOnProjectColumn(ctx, ctx.Doer, column, sortedIssueIDs); err != nil { ctx.ServerError("MoveIssuesOnProjectColumn", err) return } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index ce459f23b9323..81c6aa9f4057a 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1680,6 +1680,11 @@ func ViewIssue(ctx *context.Context) { if comment.ProjectID > 0 && comment.Project == nil { comment.Project = ghostProject } + } else if comment.Type == issues_model.CommentTypeProjectColumn { + if err = comment.LoadProject(ctx); err != nil { + ctx.ServerError("LoadProject", err) + return + } } else if comment.Type == issues_model.CommentTypeAssignees || comment.Type == issues_model.CommentTypeReviewRequest { if err = comment.LoadAssigneeUserAndTeam(ctx); err != nil { ctx.ServerError("LoadAssigneeUserAndTeam", err) diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 9ce5535a0e4a1..84bcb5ead5bbd 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -25,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" + project_service "code.gitea.io/gitea/services/projects" ) const ( @@ -662,7 +663,7 @@ func MoveIssues(ctx *context.Context) { } } - if err = project_model.MoveIssuesOnProjectColumn(ctx, column, sortedIssueIDs); err != nil { + if err = project_service.MoveIssuesOnProjectColumn(ctx, ctx.Doer, column, sortedIssueIDs); err != nil { ctx.ServerError("MoveIssuesOnProjectColumn", err) return } diff --git a/services/projects/issue.go b/services/projects/issue.go new file mode 100644 index 0000000000000..20b44552c416b --- /dev/null +++ b/services/projects/issue.go @@ -0,0 +1,76 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package project + +import ( + "context" + "fmt" + + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + project_model "code.gitea.io/gitea/models/project" + user_model "code.gitea.io/gitea/models/user" +) + +// MoveIssuesOnProjectColumn moves or keeps issues in a column and sorts them inside that column +func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, column *project_model.Column, sortedIssueIDs map[int64]int64) error { + return db.WithTx(ctx, func(ctx context.Context) error { + sess := db.GetEngine(ctx) + + issueIDs := make([]int64, 0, len(sortedIssueIDs)) + for _, issueID := range sortedIssueIDs { + issueIDs = append(issueIDs, issueID) + } + count, err := sess.Table(new(project_model.ProjectIssue)).Where("project_id=?", column.ProjectID).In("issue_id", issueIDs).Count() + if err != nil { + return err + } + if int(count) != len(sortedIssueIDs) { + return fmt.Errorf("all issues have to be added to a project first") + } + + issues, err := issues_model.GetIssuesByIDs(ctx, issueIDs) + if err != nil { + return err + } + if _, err := issues.LoadRepositories(ctx); err != nil { + return err + } + + project, err := project_model.GetProjectByID(ctx, column.ProjectID) + if err != nil { + return err + } + + for sorting, issueID := range sortedIssueIDs { + _, err = sess.Exec("UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", column.ID, sorting, issueID) + if err != nil { + return err + } + + var curIssue *issues_model.Issue + for _, issue := range issues { + if issue.ID == issueID { + curIssue = issue + break + } + } + + // add timeline to issue + if _, err := issues_model.CreateComment(ctx, &issues_model.CreateCommentOptions{ + Type: issues_model.CommentTypeProjectColumn, + Doer: doer, + Repo: curIssue.Repo, + Issue: curIssue, + ProjectID: column.ProjectID, + ProjectTitle: project.Title, + ProjectColumnID: column.ID, + ProjectColumnTitle: column.Title, + }); err != nil { + return err + } + } + return nil + }) +} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 3da2f3815ee3f..7d15898b73f26 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -600,6 +600,22 @@ {{end}} + {{else if eq .Type 31}} + {{if not $.UnitProjectsGlobalDisabled}} +
+ {{svg "octicon-project"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{$newProjectDisplayHtml := "Unknown Project"}} + {{if .Project}} + {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} + {{$newProjectDisplayHtml = printf `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}} + {{end}} + {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" (.CommentMetaData.ProjectColumnTitle|Safe) ($newProjectDisplayHtml|Safe) $createdStr}} + +
+ {{end}} {{else if eq .Type 32}}
From bb8fac849240e96d0b6355843ff20626d7280d76 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 23 Feb 2024 17:22:43 +0800 Subject: [PATCH 02/13] Fix bug --- models/issues/comment.go | 8 ++++---- models/migrations/v1_22/v287.go | 2 +- routers/web/org/projects.go | 1 + services/projects/issue.go | 9 +++++---- templates/repo/issue/view_content/comments.tmpl | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index d6e5504d72091..fafc2673c3b52 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -225,8 +225,8 @@ func (r RoleInRepo) LocaleHelper(lang translation.Locale) string { // CommentMetaData stores metadata for a comment, these data will not be changed once inserted into database type CommentMetaData struct { ProjectColumnID int64 `json:"project_column_id"` - ProjectColumnTitle string `json:"project_column_name"` - ProjectTitle string `json:"project_name"` + ProjectColumnTitle string `json:"project_column_title"` + ProjectTitle string `json:"project_title"` } // Comment represents a comment in commit and issue page. @@ -807,11 +807,11 @@ func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, } var commentMetaData *CommentMetaData - if opts.ProjectColumnID > 0 { + if opts.ProjectColumnTitle != "" { commentMetaData = &CommentMetaData{ ProjectColumnID: opts.ProjectColumnID, ProjectColumnTitle: opts.ProjectColumnTitle, - ProjectTitle: opts.ProjectColumnTitle, + ProjectTitle: opts.ProjectTitle, } } diff --git a/models/migrations/v1_22/v287.go b/models/migrations/v1_22/v287.go index 14bcaeada8724..f5264322b5290 100644 --- a/models/migrations/v1_22/v287.go +++ b/models/migrations/v1_22/v287.go @@ -1,4 +1,4 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. +// Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package v1_22 //nolint diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 75ceed459ffa1..6a3032aae963c 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -570,6 +570,7 @@ func MoveIssues(ctx *context.Context) { form := &movedIssuesForm{} if err = json.NewDecoder(ctx.Req.Body).Decode(&form); err != nil { ctx.ServerError("DecodeMovedIssuesForm", err) + return } issueIDs := make([]int64, 0, len(form.Issues)) diff --git a/services/projects/issue.go b/services/projects/issue.go index 20b44552c416b..0976eb80d5171 100644 --- a/services/projects/issue.go +++ b/services/projects/issue.go @@ -16,13 +16,14 @@ import ( // MoveIssuesOnProjectColumn moves or keeps issues in a column and sorts them inside that column func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, column *project_model.Column, sortedIssueIDs map[int64]int64) error { return db.WithTx(ctx, func(ctx context.Context) error { - sess := db.GetEngine(ctx) - issueIDs := make([]int64, 0, len(sortedIssueIDs)) for _, issueID := range sortedIssueIDs { issueIDs = append(issueIDs, issueID) } - count, err := sess.Table(new(project_model.ProjectIssue)).Where("project_id=?", column.ProjectID).In("issue_id", issueIDs).Count() + count, err := db.GetEngine(ctx). + Where("project_id=?", column.ProjectID). + In("issue_id", issueIDs). + Count(new(project_model.ProjectIssue)) if err != nil { return err } @@ -44,7 +45,7 @@ func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, colum } for sorting, issueID := range sortedIssueIDs { - _, err = sess.Exec("UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", column.ID, sorting, issueID) + _, err = db.Exec(ctx, "UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", column.ID, sorting, issueID) if err != nil { return err } diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 7d15898b73f26..346ceee6c6906 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -607,7 +607,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} {{template "shared/user/authorlink" .Poster}} - {{$newProjectDisplayHtml := "Unknown Project"}} + {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle|Safe}} {{if .Project}} {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} {{$newProjectDisplayHtml = printf `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}} From 8bd1218e8b3e2d33d6200e6b6b1f77c6c8177036 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 Feb 2024 13:19:39 +0800 Subject: [PATCH 03/13] Fix possible xss bug --- templates/repo/issue/view_content/comments.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 346ceee6c6906..e1a67cc8b6d1c 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -607,12 +607,12 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} {{template "shared/user/authorlink" .Poster}} - {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle|Safe}} + {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle}} {{if .Project}} {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} {{$newProjectDisplayHtml = printf `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}} {{end}} - {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" (.CommentMetaData.ProjectColumnTitle|Safe) ($newProjectDisplayHtml|Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" (.CommentMetaData.ProjectColumnTitle|Escape) ($newProjectDisplayHtml|Safe) $createdStr}}
{{end}} From d7f48be02f072156664f5c8707665a0cbe9aee88 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 Feb 2024 13:24:43 +0800 Subject: [PATCH 04/13] Use Escape --- templates/repo/issue/view_content/comments.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index e1a67cc8b6d1c..5c588269077e4 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -607,7 +607,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} {{template "shared/user/authorlink" .Poster}} - {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle}} + {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle | Escape}} {{if .Project}} {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} {{$newProjectDisplayHtml = printf `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}} From e4798b90e832ed0b97c60f1860a2da02ec7b527b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 Feb 2024 19:18:22 +0800 Subject: [PATCH 05/13] Use new template HTML method --- templates/repo/issue/view_content/comments.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 5c588269077e4..b5a861e5fba42 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -610,9 +610,9 @@ {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle | Escape}} {{if .Project}} {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} - {{$newProjectDisplayHtml = printf `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}} + {{$newProjectDisplayHtml = HTMLFormat `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey) .Project.Title}} {{end}} - {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" (.CommentMetaData.ProjectColumnTitle|Escape) ($newProjectDisplayHtml|Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" (.CommentMetaData.ProjectColumnTitle|Escape) $newProjectDisplayHtml $createdStr}}
{{end}} From 67dfeb2b5010b2971bb4ded5d98925406a15f18e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 29 Feb 2024 10:34:23 +0800 Subject: [PATCH 06/13] Ignore the fields on database when it's empty --- models/issues/comment.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index fafc2673c3b52..48b8e335d48ef 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -224,9 +224,9 @@ func (r RoleInRepo) LocaleHelper(lang translation.Locale) string { // CommentMetaData stores metadata for a comment, these data will not be changed once inserted into database type CommentMetaData struct { - ProjectColumnID int64 `json:"project_column_id"` - ProjectColumnTitle string `json:"project_column_title"` - ProjectTitle string `json:"project_title"` + ProjectColumnID int64 `json:"project_column_id,omitempty"` + ProjectColumnTitle string `json:"project_column_title,omitempty"` + ProjectTitle string `json:"project_title,omitempty"` } // Comment represents a comment in commit and issue page. From 8b4cc81ce5db2554b06f94cff77f77ff9a9b5bae Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 25 Feb 2024 23:35:41 +0800 Subject: [PATCH 07/13] Apply suggestions from code review --- templates/repo/issue/view_content/comments.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index b5a861e5fba42..89877e4beb974 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -607,12 +607,12 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} {{template "shared/user/authorlink" .Poster}} - {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle | Escape}} + {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle}} {{if .Project}} {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} {{$newProjectDisplayHtml = HTMLFormat `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey) .Project.Title}} {{end}} - {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" (.CommentMetaData.ProjectColumnTitle|Escape) $newProjectDisplayHtml $createdStr}} + {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" .CommentMetaData.ProjectColumnTitle $newProjectDisplayHtml $createdStr}} {{end}} From 45ac27e28af2e3b1536da2fc8f410b6aa5ea2703 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 25 Feb 2024 23:37:21 +0800 Subject: [PATCH 08/13] Update templates/repo/issue/view_content/comments.tmpl --- templates/repo/issue/view_content/comments.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 89877e4beb974..879df0b2a1545 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -607,12 +607,12 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} {{template "shared/user/authorlink" .Poster}} - {{$newProjectDisplayHtml := .CommentMetaData.ProjectTitle}} + {{$newProjectDisplay := .CommentMetaData.ProjectTitle}} {{if .Project}} {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} - {{$newProjectDisplayHtml = HTMLFormat `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey) .Project.Title}} + {{$newProjectDisplay = HTMLFormat `%s %s` (svg .Project.IconName) (.Project.Link ctx) (ctx.Locale.Tr $trKey) .Project.Title}} {{end}} - {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" .CommentMetaData.ProjectColumnTitle $newProjectDisplayHtml $createdStr}} + {{ctx.Locale.Tr "repo.issues.move_to_column_of_project" .CommentMetaData.ProjectColumnTitle $newProjectDisplay $createdStr}} {{end}} From 58b4698ad5bba55e4b61534fa9b62099340622ca Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 8 Apr 2024 14:48:11 +0800 Subject: [PATCH 09/13] Fix metadata name --- models/migrations/v1_23/v300.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/models/migrations/v1_23/v300.go b/models/migrations/v1_23/v300.go index acb4e32c41231..6d93f4c4f0afc 100644 --- a/models/migrations/v1_23/v300.go +++ b/models/migrations/v1_23/v300.go @@ -8,9 +8,9 @@ import ( // CommentMetaData stores metadata for a comment, these data will not be changed once inserted into database type CommentMetaData struct { - ProjectColumnID int64 `json:"project_column_id"` - ProjectColumnName string `json:"project_column_name"` - ProjectName string `json:"project_name"` + ProjectColumnID int64 `json:"project_column_id"` + ProjectColumnTitle string `json:"project_column_title"` + ProjectTitle string `json:"project_title"` } func AddCommentMetaDataColumn(x *xorm.Engine) error { From 2118c6b67884d4866a022124b969fcd1290a2669 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 2 May 2024 13:23:31 +0800 Subject: [PATCH 10/13] Update models/migrations/v1_23/v297.go Co-authored-by: yp05327 <576951401@qq.com> --- models/migrations/v1_23/v300.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v1_23/v300.go b/models/migrations/v1_23/v300.go index 6d93f4c4f0afc..94b6c29e19b1d 100644 --- a/models/migrations/v1_23/v300.go +++ b/models/migrations/v1_23/v300.go @@ -15,7 +15,7 @@ type CommentMetaData struct { func AddCommentMetaDataColumn(x *xorm.Engine) error { type Comment struct { - CommentMetaData CommentMetaData `xorm:"JSON TEXT"` // put all non-index metadata in a single field + CommentMetaData *CommentMetaData `xorm:"JSON TEXT"` // put all non-index metadata in a single field } return x.Sync(new(Comment)) From c43f7ed0ca54c2bf3d091584765270c5008535e2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 28 May 2024 00:04:04 +0800 Subject: [PATCH 11/13] Fix lint --- models/migrations/v1_22/v287.go | 2 +- models/migrations/v1_23/v300.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/models/migrations/v1_22/v287.go b/models/migrations/v1_22/v287.go index f5264322b5290..14bcaeada8724 100644 --- a/models/migrations/v1_22/v287.go +++ b/models/migrations/v1_22/v287.go @@ -1,4 +1,4 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package v1_22 //nolint diff --git a/models/migrations/v1_23/v300.go b/models/migrations/v1_23/v300.go index 94b6c29e19b1d..adfe917d3f241 100644 --- a/models/migrations/v1_23/v300.go +++ b/models/migrations/v1_23/v300.go @@ -1,5 +1,6 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT + package v1_23 //nolint import ( From b1a2f40e1fcdee1a651f1db3e912986e2081342f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 28 May 2024 11:19:57 +0800 Subject: [PATCH 12/13] Follow yp05327's suggestion --- models/migrations/v1_22/v287.go | 1 + models/project/issue.go | 24 ------------------------ services/projects/issue.go | 13 ++++++------- 3 files changed, 7 insertions(+), 31 deletions(-) diff --git a/models/migrations/v1_22/v287.go b/models/migrations/v1_22/v287.go index 14bcaeada8724..c8b1593286945 100644 --- a/models/migrations/v1_22/v287.go +++ b/models/migrations/v1_22/v287.go @@ -1,5 +1,6 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT + package v1_22 //nolint import ( diff --git a/models/project/issue.go b/models/project/issue.go index 3361b533b972c..1c31b154ced01 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -76,30 +76,6 @@ func (p *Project) NumOpenIssues(ctx context.Context) int { return int(c) } -// MoveIssuesOnProjectColumn moves or keeps issues in a column and sorts them inside that column -func MoveIssuesOnProjectColumn(ctx context.Context, column *Column, sortedIssueIDs map[int64]int64) error { - return db.WithTx(ctx, func(ctx context.Context) error { - sess := db.GetEngine(ctx) - issueIDs := util.ValuesOfMap(sortedIssueIDs) - - count, err := sess.Table(new(ProjectIssue)).Where("project_id=?", column.ProjectID).In("issue_id", issueIDs).Count() - if err != nil { - return err - } - if int(count) != len(sortedIssueIDs) { - return fmt.Errorf("all issues have to be added to a project first") - } - - for sorting, issueID := range sortedIssueIDs { - _, err = sess.Exec("UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", column.ID, sorting, issueID) - if err != nil { - return err - } - } - return nil - }) -} - func (c *Column) moveIssuesToAnotherColumn(ctx context.Context, newColumn *Column) error { if c.ProjectID != newColumn.ProjectID { return fmt.Errorf("columns have to be in the same project") diff --git a/services/projects/issue.go b/services/projects/issue.go index 0976eb80d5171..d5d3363859c24 100644 --- a/services/projects/issue.go +++ b/services/projects/issue.go @@ -44,19 +44,18 @@ func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, colum return err } + issuesMap := make(map[int64]*issues_model.Issue, len(issues)) + for _, issue := range issues { + issuesMap[issue.ID] = issue + } + for sorting, issueID := range sortedIssueIDs { _, err = db.Exec(ctx, "UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", column.ID, sorting, issueID) if err != nil { return err } - var curIssue *issues_model.Issue - for _, issue := range issues { - if issue.ID == issueID { - curIssue = issue - break - } - } + curIssue := issuesMap[issueID] // add timeline to issue if _, err := issues_model.CreateComment(ctx, &issues_model.CreateCommentOptions{ From e1d45e15be24e8f087e38e91d17f45dcb40a7868 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 8 Aug 2024 10:57:22 -0700 Subject: [PATCH 13/13] Fix possible panic --- services/projects/issue.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/projects/issue.go b/services/projects/issue.go index d5d3363859c24..db1621a39f933 100644 --- a/services/projects/issue.go +++ b/services/projects/issue.go @@ -50,13 +50,16 @@ func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, colum } for sorting, issueID := range sortedIssueIDs { + curIssue := issuesMap[issueID] + if curIssue == nil { + continue + } + _, err = db.Exec(ctx, "UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", column.ID, sorting, issueID) if err != nil { return err } - curIssue := issuesMap[issueID] - // add timeline to issue if _, err := issues_model.CreateComment(ctx, &issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeProjectColumn,