mirror of
https://github.com/go-gitea/gitea.git
synced 2024-09-28 03:06:03 -04:00
Add issue comment when moving issues from one column to another of the project
This commit is contained in:
parent
cd7d1314fc
commit
5f5212ca60
@ -222,6 +222,13 @@ func (r RoleInRepo) LocaleHelper(lang translation.Locale) string {
|
|||||||
return lang.TrString("repo.issues.role." + string(r) + "_helper")
|
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.
|
// Comment represents a comment in commit and issue page.
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
@ -295,6 +302,8 @@ type Comment struct {
|
|||||||
RefAction references.XRefAction `xorm:"SMALLINT"` // What happens if RefIssueID resolves
|
RefAction references.XRefAction `xorm:"SMALLINT"` // What happens if RefIssueID resolves
|
||||||
RefIsPull bool
|
RefIsPull bool
|
||||||
|
|
||||||
|
CommentMetaData *CommentMetaData `xorm:"JSON TEXT"` // put all non-index metadata in a single field
|
||||||
|
|
||||||
RefRepo *repo_model.Repository `xorm:"-"`
|
RefRepo *repo_model.Repository `xorm:"-"`
|
||||||
RefIssue *Issue `xorm:"-"`
|
RefIssue *Issue `xorm:"-"`
|
||||||
RefComment *Comment `xorm:"-"`
|
RefComment *Comment `xorm:"-"`
|
||||||
@ -797,6 +806,15 @@ func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment,
|
|||||||
LabelID = opts.Label.ID
|
LabelID = opts.Label.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var commentMetaData *CommentMetaData
|
||||||
|
if opts.ProjectColumnID > 0 {
|
||||||
|
commentMetaData = &CommentMetaData{
|
||||||
|
ProjectColumnID: opts.ProjectColumnID,
|
||||||
|
ProjectColumnTitle: opts.ProjectColumnTitle,
|
||||||
|
ProjectTitle: opts.ProjectColumnTitle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
comment := &Comment{
|
comment := &Comment{
|
||||||
Type: opts.Type,
|
Type: opts.Type,
|
||||||
PosterID: opts.Doer.ID,
|
PosterID: opts.Doer.ID,
|
||||||
@ -830,6 +848,7 @@ func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment,
|
|||||||
RefIsPull: opts.RefIsPull,
|
RefIsPull: opts.RefIsPull,
|
||||||
IsForcePush: opts.IsForcePush,
|
IsForcePush: opts.IsForcePush,
|
||||||
Invalidated: opts.Invalidated,
|
Invalidated: opts.Invalidated,
|
||||||
|
CommentMetaData: commentMetaData,
|
||||||
}
|
}
|
||||||
if _, err = e.Insert(comment); err != nil {
|
if _, err = e.Insert(comment); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -982,34 +1001,37 @@ type CreateCommentOptions struct {
|
|||||||
Issue *Issue
|
Issue *Issue
|
||||||
Label *Label
|
Label *Label
|
||||||
|
|
||||||
DependentIssueID int64
|
DependentIssueID int64
|
||||||
OldMilestoneID int64
|
OldMilestoneID int64
|
||||||
MilestoneID int64
|
MilestoneID int64
|
||||||
OldProjectID int64
|
OldProjectID int64
|
||||||
ProjectID int64
|
ProjectID int64
|
||||||
TimeID int64
|
ProjectTitle string
|
||||||
AssigneeID int64
|
ProjectColumnID int64
|
||||||
AssigneeTeamID int64
|
ProjectColumnTitle string
|
||||||
RemovedAssignee bool
|
TimeID int64
|
||||||
OldTitle string
|
AssigneeID int64
|
||||||
NewTitle string
|
AssigneeTeamID int64
|
||||||
OldRef string
|
RemovedAssignee bool
|
||||||
NewRef string
|
OldTitle string
|
||||||
CommitID int64
|
NewTitle string
|
||||||
CommitSHA string
|
OldRef string
|
||||||
Patch string
|
NewRef string
|
||||||
LineNum int64
|
CommitID int64
|
||||||
TreePath string
|
CommitSHA string
|
||||||
ReviewID int64
|
Patch string
|
||||||
Content string
|
LineNum int64
|
||||||
Attachments []string // UUIDs of attachments
|
TreePath string
|
||||||
RefRepoID int64
|
ReviewID int64
|
||||||
RefIssueID int64
|
Content string
|
||||||
RefCommentID int64
|
Attachments []string // UUIDs of attachments
|
||||||
RefAction references.XRefAction
|
RefRepoID int64
|
||||||
RefIsPull bool
|
RefIssueID int64
|
||||||
IsForcePush bool
|
RefCommentID int64
|
||||||
Invalidated bool
|
RefAction references.XRefAction
|
||||||
|
RefIsPull bool
|
||||||
|
IsForcePush bool
|
||||||
|
Invalidated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommentByID returns the comment by given ID.
|
// GetCommentByID returns the comment by given ID.
|
||||||
|
@ -434,6 +434,7 @@ func (issues IssueList) loadComments(ctx context.Context, cond builder.Cond) (er
|
|||||||
Join("INNER", "issue", "issue.id = comment.issue_id").
|
Join("INNER", "issue", "issue.id = comment.issue_id").
|
||||||
In("issue.id", issuesIDs[:limit]).
|
In("issue.id", issuesIDs[:limit]).
|
||||||
Where(cond).
|
Where(cond).
|
||||||
|
NoAutoCondition().
|
||||||
Rows(new(Comment))
|
Rows(new(Comment))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -591,6 +591,8 @@ var migrations = []Migration{
|
|||||||
|
|
||||||
// v299 -> v300
|
// v299 -> v300
|
||||||
NewMigration("Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment),
|
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
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package v1_22 //nolint
|
package v1_22 //nolint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
22
models/migrations/v1_23/v300.go
Normal file
22
models/migrations/v1_23/v300.go
Normal file
@ -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))
|
||||||
|
}
|
@ -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_remove_labels = added %s and removed %s labels %s
|
||||||
issues.add_milestone_at = `added this to the <b>%s</b> milestone %s`
|
issues.add_milestone_at = `added this to the <b>%s</b> milestone %s`
|
||||||
issues.add_project_at = `added this to the <b>%s</b> project %s`
|
issues.add_project_at = `added this to the <b>%s</b> project %s`
|
||||||
|
issues.move_to_column_of_project = `moved this to %s in %s on %s`
|
||||||
issues.change_milestone_at = `modified the milestone from <b>%s</b> to <b>%s</b> %s`
|
issues.change_milestone_at = `modified the milestone from <b>%s</b> to <b>%s</b> %s`
|
||||||
issues.change_project_at = `modified the project from <b>%s</b> to <b>%s</b> %s`
|
issues.change_project_at = `modified the project from <b>%s</b> to <b>%s</b> %s`
|
||||||
issues.remove_milestone_at = `removed this from the <b>%s</b> milestone %s`
|
issues.remove_milestone_at = `removed this from the <b>%s</b> milestone %s`
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
|
project_service "code.gitea.io/gitea/services/projects"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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)
|
ctx.ServerError("MoveIssuesOnProjectColumn", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1680,6 +1680,11 @@ func ViewIssue(ctx *context.Context) {
|
|||||||
if comment.ProjectID > 0 && comment.Project == nil {
|
if comment.ProjectID > 0 && comment.Project == nil {
|
||||||
comment.Project = ghostProject
|
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 {
|
} else if comment.Type == issues_model.CommentTypeAssignees || comment.Type == issues_model.CommentTypeReviewRequest {
|
||||||
if err = comment.LoadAssigneeUserAndTeam(ctx); err != nil {
|
if err = comment.LoadAssigneeUserAndTeam(ctx); err != nil {
|
||||||
ctx.ServerError("LoadAssigneeUserAndTeam", err)
|
ctx.ServerError("LoadAssigneeUserAndTeam", err)
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
|
project_service "code.gitea.io/gitea/services/projects"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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)
|
ctx.ServerError("MoveIssuesOnProjectColumn", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
76
services/projects/issue.go
Normal file
76
services/projects/issue.go
Normal file
@ -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
|
||||||
|
})
|
||||||
|
}
|
@ -600,6 +600,22 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{else if eq .Type 31}}
|
||||||
|
{{if not $.UnitProjectsGlobalDisabled}}
|
||||||
|
<div class="timeline-item event" id="{{.HashTag}}">
|
||||||
|
<span class="badge">{{svg "octicon-project"}}</span>
|
||||||
|
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
||||||
|
<span class="text grey muted-links">
|
||||||
|
{{template "shared/user/authorlink" .Poster}}
|
||||||
|
{{$newProjectDisplayHtml := "Unknown Project"}}
|
||||||
|
{{if .Project}}
|
||||||
|
{{$trKey := printf "projects.type-%d.display_name" .Project.Type}}
|
||||||
|
{{$newProjectDisplayHtml = printf `%s <a href="%s"><span data-tooltip-content="%s">%s</span></a>` (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}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
{{else if eq .Type 32}}
|
{{else if eq .Type 32}}
|
||||||
<div class="timeline-item-group">
|
<div class="timeline-item-group">
|
||||||
<div class="timeline-item event" id="{{.HashTag}}">
|
<div class="timeline-item event" id="{{.HashTag}}">
|
||||||
|
Loading…
Reference in New Issue
Block a user