mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	add milestone changed traker on issue view (#804)
This commit is contained in:
		| @@ -739,7 +739,7 @@ type NewIssueOptions struct { | ||||
| 	IsPull      bool | ||||
| } | ||||
|  | ||||
| func newIssue(e *xorm.Session, opts NewIssueOptions) (err error) { | ||||
| func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { | ||||
| 	opts.Issue.Title = strings.TrimSpace(opts.Issue.Title) | ||||
| 	opts.Issue.Index = opts.Repo.NextIssueIndex() | ||||
|  | ||||
| @@ -754,9 +754,6 @@ func newIssue(e *xorm.Session, opts NewIssueOptions) (err error) { | ||||
| 		if milestone != nil { | ||||
| 			opts.Issue.MilestoneID = milestone.ID | ||||
| 			opts.Issue.Milestone = milestone | ||||
| 			if err = changeMilestoneAssign(e, opts.Issue, -1); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -785,6 +782,12 @@ func newIssue(e *xorm.Session, opts NewIssueOptions) (err error) { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if opts.Issue.MilestoneID > 0 { | ||||
| 		if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if opts.IsPull { | ||||
| 		_, err = e.Exec("UPDATE `repository` SET num_pulls = num_pulls + 1 WHERE id = ?", opts.Issue.RepoID) | ||||
| 	} else { | ||||
| @@ -849,7 +852,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if err = newIssue(sess, NewIssueOptions{ | ||||
| 	if err = newIssue(sess, issue.Poster, NewIssueOptions{ | ||||
| 		Repo:        repo, | ||||
| 		Issue:       issue, | ||||
| 		LableIDs:    labelIDs, | ||||
| @@ -1773,7 +1776,7 @@ func ChangeMilestoneIssueStats(issue *Issue) (err error) { | ||||
| 	return sess.Commit() | ||||
| } | ||||
|  | ||||
| func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64) error { | ||||
| func changeMilestoneAssign(e *xorm.Session, doer *User, issue *Issue, oldMilestoneID int64) error { | ||||
| 	if oldMilestoneID > 0 { | ||||
| 		m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID) | ||||
| 		if err != nil { | ||||
| @@ -1810,18 +1813,28 @@ func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := issue.loadRepo(e); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if oldMilestoneID > 0 || issue.MilestoneID > 0 { | ||||
| 		if _, err := createMilestoneComment(e, doer, issue.Repo, issue, oldMilestoneID, issue.MilestoneID); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return updateIssue(e, issue) | ||||
| } | ||||
|  | ||||
| // ChangeMilestoneAssign changes assignment of milestone for issue. | ||||
| func ChangeMilestoneAssign(issue *Issue, oldMilestoneID int64) (err error) { | ||||
| func ChangeMilestoneAssign(issue *Issue, doer *User, oldMilestoneID int64) (err error) { | ||||
| 	sess := x.NewSession() | ||||
| 	defer sess.Close() | ||||
| 	if err = sess.Begin(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if err = changeMilestoneAssign(sess, issue, oldMilestoneID); err != nil { | ||||
| 	if err = changeMilestoneAssign(sess, doer, issue, oldMilestoneID); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sess.Commit() | ||||
|   | ||||
| @@ -38,6 +38,8 @@ const ( | ||||
| 	CommentTypePullRef | ||||
| 	// Labels changed | ||||
| 	CommentTypeLabel | ||||
| 	// Milestone changed | ||||
| 	CommentTypeMilestone | ||||
| ) | ||||
|  | ||||
| // CommentTag defines comment tag type | ||||
| @@ -58,9 +60,13 @@ type Comment struct { | ||||
| 	PosterID        int64 `xorm:"INDEX"` | ||||
| 	Poster          *User `xorm:"-"` | ||||
| 	IssueID         int64 `xorm:"INDEX"` | ||||
| 	CommitID        int64 | ||||
| 	LabelID         int64 | ||||
| 	Label           *Label `xorm:"-"` | ||||
| 	OldMilestoneID  int64 | ||||
| 	MilestoneID     int64 | ||||
| 	OldMilestone    *Milestone `xorm:"-"` | ||||
| 	Milestone       *Milestone `xorm:"-"` | ||||
| 	CommitID        int64 | ||||
| 	Line            int64 | ||||
| 	Content         string `xorm:"TEXT"` | ||||
| 	RenderedContent string `xorm:"-"` | ||||
| @@ -204,6 +210,36 @@ func (c *Comment) LoadLabel() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // LoadMilestone if comment.Type is CommentTypeMilestone, then load milestone | ||||
| func (c *Comment) LoadMilestone() error { | ||||
| 	if c.OldMilestoneID > 0 { | ||||
| 		var oldMilestone Milestone | ||||
| 		has, err := x.ID(c.OldMilestoneID).Get(&oldMilestone) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} else if !has { | ||||
| 			return ErrMilestoneNotExist{ | ||||
| 				ID: c.OldMilestoneID, | ||||
| 			} | ||||
| 		} | ||||
| 		c.OldMilestone = &oldMilestone | ||||
| 	} | ||||
|  | ||||
| 	if c.MilestoneID > 0 { | ||||
| 		var milestone Milestone | ||||
| 		has, err := x.ID(c.MilestoneID).Get(&milestone) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} else if !has { | ||||
| 			return ErrMilestoneNotExist{ | ||||
| 				ID: c.MilestoneID, | ||||
| 			} | ||||
| 		} | ||||
| 		c.Milestone = &milestone | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // MailParticipants sends new comment emails to repository watchers | ||||
| // and mentioned people. | ||||
| func (c *Comment) MailParticipants(e Engine, opType ActionType, issue *Issue) (err error) { | ||||
| @@ -238,6 +274,8 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err | ||||
| 		Poster:         opts.Doer, | ||||
| 		IssueID:        opts.Issue.ID, | ||||
| 		LabelID:        LabelID, | ||||
| 		OldMilestoneID: opts.OldMilestoneID, | ||||
| 		MilestoneID:    opts.MilestoneID, | ||||
| 		CommitID:       opts.CommitID, | ||||
| 		CommitSHA:      opts.CommitSHA, | ||||
| 		Line:           opts.LineNum, | ||||
| @@ -367,6 +405,17 @@ func createLabelComment(e *xorm.Session, doer *User, repo *Repository, issue *Is | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func createMilestoneComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue, oldMilestoneID, milestoneID int64) (*Comment, error) { | ||||
| 	return createComment(e, &CreateCommentOptions{ | ||||
| 		Type:           CommentTypeMilestone, | ||||
| 		Doer:           doer, | ||||
| 		Repo:           repo, | ||||
| 		Issue:          issue, | ||||
| 		OldMilestoneID: oldMilestoneID, | ||||
| 		MilestoneID:    milestoneID, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // CreateCommentOptions defines options for creating comment | ||||
| type CreateCommentOptions struct { | ||||
| 	Type  CommentType | ||||
| @@ -375,6 +424,8 @@ type CreateCommentOptions struct { | ||||
| 	Issue *Issue | ||||
| 	Label *Label | ||||
|  | ||||
| 	OldMilestoneID int64 | ||||
| 	MilestoneID    int64 | ||||
| 	CommitID       int64 | ||||
| 	CommitSHA      string | ||||
| 	LineNum        int64 | ||||
|   | ||||
| @@ -470,7 +470,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if err = newIssue(sess, NewIssueOptions{ | ||||
| 	if err = newIssue(sess, pull.Poster, NewIssueOptions{ | ||||
| 		Repo:        repo, | ||||
| 		Issue:       pull, | ||||
| 		LableIDs:    labelIDs, | ||||
|   | ||||
| @@ -543,6 +543,9 @@ issues.label_templates.use = Use this label set | ||||
| issues.label_templates.fail_to_load_file = Failed to load label template file '%s': %v | ||||
| issues.add_label_at = `added the <div class="ui label" style="color: %s; background-color: %s">%s</div> label %s` | ||||
| issues.remove_label_at = `removed the <div class="ui label" style="color: %s; background-color: %s">%s</div> label %s` | ||||
| issues.add_milestone_at = `added this to the <b>%s</b> milestone %s` | ||||
| issues.change_milestone_at = `modified the milestone from <b>%s</b> to <b>%s</b> %s` | ||||
| issues.remove_milestone_at = `removed this from the <b>%s</b> milestone %s` | ||||
| issues.open_tab = %d Open | ||||
| issues.close_tab = %d Closed | ||||
| issues.filter_label = Label | ||||
|   | ||||
| @@ -503,6 +503,9 @@ issues.label_templates.use=加载标签模板 | ||||
| issues.label_templates.fail_to_load_file=加载标签模板文件 '%s' 时发生错误:%v | ||||
| issues.add_label_at = ` %[4]s 添加了标签 <div class="ui label" style="color: %[1]s; background-color: %[2]s">%[3]s</div>` | ||||
| issues.remove_label_at = ` %[4]s 删除了标签 <div class="ui label" style="color: %[1]s; background-color: %[2]s">%[3]s</div>` | ||||
| issues.add_milestone_at = ` %[2]s 添加了里程碑 <b>%[1]s</b>` | ||||
| issues.change_milestone_at = `%[3]s 修改了里程碑从 <b>%[1]s</b> 到 <b>%[2]s</b>` | ||||
| issues.remove_milestone_at = `%[2]s 删除了里程碑 <b>%[1]s</b>` | ||||
| issues.open_tab=%d 个开启中 | ||||
| issues.close_tab=%d 个已关闭 | ||||
| issues.filter_label=标签筛选 | ||||
|   | ||||
| @@ -168,6 +168,12 @@ function initCommentForm() { | ||||
|         var $list = $('.ui' + select_id + '.list'); | ||||
|         var hasUpdateAction = $menu.data('action') == 'update'; | ||||
|  | ||||
|         $(select_id).dropdown('setting', 'onHide', function(){ | ||||
|             if (hasUpdateAction) { | ||||
|                 location.reload(); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         $menu.find('.item:not(.no-select)').click(function () { | ||||
|             $(this).parent().find('.item').each(function () { | ||||
|                 $(this).removeClass('selected active') | ||||
|   | ||||
| @@ -168,7 +168,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) { | ||||
| 		issue.MilestoneID != *form.Milestone { | ||||
| 		oldMilestoneID := issue.MilestoneID | ||||
| 		issue.MilestoneID = *form.Milestone | ||||
| 		if err = models.ChangeMilestoneAssign(issue, oldMilestoneID); err != nil { | ||||
| 		if err = models.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil { | ||||
| 			ctx.Error(500, "ChangeMilestoneAssign", err) | ||||
| 			return | ||||
| 		} | ||||
|   | ||||
| @@ -241,7 +241,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) { | ||||
| 		issue.MilestoneID != form.Milestone { | ||||
| 		oldMilestoneID := issue.MilestoneID | ||||
| 		issue.MilestoneID = form.Milestone | ||||
| 		if err = models.ChangeMilestoneAssign(issue, oldMilestoneID); err != nil { | ||||
| 		if err = models.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil { | ||||
| 			ctx.Error(500, "ChangeMilestoneAssign", err) | ||||
| 			return | ||||
| 		} | ||||
|   | ||||
| @@ -384,22 +384,27 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64 | ||||
| 		return nil, 0, 0 | ||||
| 	} | ||||
|  | ||||
| 	var labelIDs []int64 | ||||
| 	hasSelected := false | ||||
| 	// Check labels. | ||||
| 	labelIDs, err := base.StringsToInt64s(strings.Split(form.LabelIDs, ",")) | ||||
| 	if len(form.LabelIDs) > 0 { | ||||
| 		labelIDs, err = base.StringsToInt64s(strings.Split(form.LabelIDs, ",")) | ||||
| 		if err != nil { | ||||
| 			return nil, 0, 0 | ||||
| 		} | ||||
| 		labelIDMark := base.Int64sToMap(labelIDs) | ||||
| 	hasSelected := false | ||||
|  | ||||
| 		for i := range labels { | ||||
| 			if labelIDMark[labels[i].ID] { | ||||
| 				labels[i].IsChecked = true | ||||
| 				hasSelected = true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ctx.Data["Labels"] = labels | ||||
| 	ctx.Data["HasSelectedLabel"] = hasSelected | ||||
| 	ctx.Data["label_ids"] = form.LabelIDs | ||||
| 	ctx.Data["Labels"] = labels | ||||
|  | ||||
| 	// Check milestone. | ||||
| 	milestoneID := form.MilestoneID | ||||
| @@ -617,6 +622,11 @@ func ViewIssue(ctx *context.Context) { | ||||
| 				ctx.Handle(500, "LoadLabel", err) | ||||
| 				return | ||||
| 			} | ||||
| 		} else if comment.Type == models.CommentTypeMilestone { | ||||
| 			if err = comment.LoadMilestone(); err != nil { | ||||
| 				ctx.Handle(500, "LoadMilestone", err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -625,7 +635,6 @@ func ViewIssue(ctx *context.Context) { | ||||
| 		canDelete := false | ||||
|  | ||||
| 		if ctx.IsSigned && pull.HeadBranch != "master" { | ||||
|  | ||||
| 			if err := pull.GetHeadRepo(); err != nil { | ||||
| 				log.Error(4, "GetHeadRepo: %v", err) | ||||
| 			} else if ctx.User.IsWriterOfRepo(pull.HeadRepo) { | ||||
| @@ -729,7 +738,7 @@ func UpdateIssueMilestone(ctx *context.Context) { | ||||
|  | ||||
| 	// Not check for invalid milestone id and give responsibility to owners. | ||||
| 	issue.MilestoneID = milestoneID | ||||
| 	if err := models.ChangeMilestoneAssign(issue, oldMilestoneID); err != nil { | ||||
| 	if err := models.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil { | ||||
| 		ctx.Handle(500, "ChangeMilestoneAssign", err) | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -153,6 +153,15 @@ | ||||
| 						<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a> | ||||
| 						{{if .Content}}{{$.i18n.Tr "repo.issues.add_label_at" .Label.ForegroundColor .Label.Color .Label.Name $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_label_at" .Label.ForegroundColor .Label.Color .Label.Name $createdStr | Safe}}{{end}}</span> | ||||
| 					</div> | ||||
| 				{{else if eq .Type 8}} | ||||
| 					<div class="event"> | ||||
| 						<span class="octicon octicon-primitive-dot"></span> | ||||
| 						<a class="ui avatar image" href="{{.Poster.HomeLink}}"> | ||||
| 							<img src="{{.Poster.RelAvatarLink}}"> | ||||
| 						</a> | ||||
| 						<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a> | ||||
| 						{{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.change_milestone_at" .OldMilestone.Name .Milestone.Name $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_milestone_at" .OldMilestone.Name $createdStr | Safe}}{{end}}{{else if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.add_milestone_at" .Milestone.Name $createdStr | Safe}}{{end}}</span> | ||||
| 					</div> | ||||
| 				{{end}} | ||||
|  | ||||
| 			{{end}} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user