summaryrefslogtreecommitdiffstats
path: root/routers/repo/milestone.go
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2018-11-29 09:46:30 +0800
committerGitHub <noreply@github.com>2018-11-29 09:46:30 +0800
commit2dc805c0c6e85099f3f346ba78f3a52abf032ce4 (patch)
tree2adeae8beaa207c80908914d3f6e48d82e2ae21d /routers/repo/milestone.go
parentd5d847e5c4f0cf1470fc51f96d57917e4d9f5d83 (diff)
downloadgitea-2dc805c0c6e85099f3f346ba78f3a52abf032ce4.tar.gz
gitea-2dc805c0c6e85099f3f346ba78f3a52abf032ce4.zip
Milestone issues and pull requests (#5293)
* add milestone issues and pulls page instead of redirecting issues page * add milestone when creating issue from milestone page * refactor to merge similiar codes as a new function issues * remove milestone info on milestone issues list * fix missing params
Diffstat (limited to 'routers/repo/milestone.go')
-rw-r--r--routers/repo/milestone.go262
1 files changed, 262 insertions, 0 deletions
diff --git a/routers/repo/milestone.go b/routers/repo/milestone.go
new file mode 100644
index 0000000000..eb2141e995
--- /dev/null
+++ b/routers/repo/milestone.go
@@ -0,0 +1,262 @@
+// Copyright 2018 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "time"
+
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/auth"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/markup/markdown"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
+ "github.com/Unknwon/paginater"
+)
+
+const (
+ tplMilestone base.TplName = "repo/issue/milestones"
+ tplMilestoneNew base.TplName = "repo/issue/milestone_new"
+ tplMilestoneEdit base.TplName = "repo/issue/milestone_edit"
+ tplMilestoneIssues base.TplName = "repo/issue/milestone_issues"
+)
+
+// Milestones render milestones page
+func Milestones(ctx *context.Context) {
+ ctx.Data["Title"] = ctx.Tr("repo.milestones")
+ ctx.Data["PageIsIssueList"] = true
+ ctx.Data["PageIsMilestones"] = true
+
+ isShowClosed := ctx.Query("state") == "closed"
+ openCount, closedCount, err := models.MilestoneStats(ctx.Repo.Repository.ID)
+ if err != nil {
+ ctx.ServerError("MilestoneStats", err)
+ return
+ }
+ ctx.Data["OpenCount"] = openCount
+ ctx.Data["ClosedCount"] = closedCount
+
+ sortType := ctx.Query("sort")
+ page := ctx.QueryInt("page")
+ if page <= 1 {
+ page = 1
+ }
+
+ var total int
+ if !isShowClosed {
+ total = int(openCount)
+ } else {
+ total = int(closedCount)
+ }
+ ctx.Data["Page"] = paginater.New(total, setting.UI.IssuePagingNum, page, 5)
+
+ miles, err := models.GetMilestones(ctx.Repo.Repository.ID, page, isShowClosed, sortType)
+ if err != nil {
+ ctx.ServerError("GetMilestones", err)
+ return
+ }
+ if ctx.Repo.Repository.IsTimetrackerEnabled() {
+ if miles.LoadTotalTrackedTimes(); err != nil {
+ ctx.ServerError("LoadTotalTrackedTimes", err)
+ return
+ }
+ }
+ for _, m := range miles {
+ m.RenderedContent = string(markdown.Render([]byte(m.Content), ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas()))
+ }
+ ctx.Data["Milestones"] = miles
+
+ if isShowClosed {
+ ctx.Data["State"] = "closed"
+ } else {
+ ctx.Data["State"] = "open"
+ }
+
+ ctx.Data["SortType"] = sortType
+ ctx.Data["IsShowClosed"] = isShowClosed
+ ctx.HTML(200, tplMilestone)
+}
+
+// NewMilestone render creating milestone page
+func NewMilestone(ctx *context.Context) {
+ ctx.Data["Title"] = ctx.Tr("repo.milestones.new")
+ ctx.Data["PageIsIssueList"] = true
+ ctx.Data["PageIsMilestones"] = true
+ ctx.Data["RequireDatetimepicker"] = true
+ ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language())
+ ctx.HTML(200, tplMilestoneNew)
+}
+
+// NewMilestonePost response for creating milestone
+func NewMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
+ ctx.Data["Title"] = ctx.Tr("repo.milestones.new")
+ ctx.Data["PageIsIssueList"] = true
+ ctx.Data["PageIsMilestones"] = true
+ ctx.Data["RequireDatetimepicker"] = true
+ ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language())
+
+ if ctx.HasError() {
+ ctx.HTML(200, tplMilestoneNew)
+ return
+ }
+
+ if len(form.Deadline) == 0 {
+ form.Deadline = "9999-12-31"
+ }
+ deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local)
+ if err != nil {
+ ctx.Data["Err_Deadline"] = true
+ ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form)
+ return
+ }
+
+ if err = models.NewMilestone(&models.Milestone{
+ RepoID: ctx.Repo.Repository.ID,
+ Name: form.Title,
+ Content: form.Content,
+ DeadlineUnix: util.TimeStamp(deadline.Unix()),
+ }); err != nil {
+ ctx.ServerError("NewMilestone", err)
+ return
+ }
+
+ ctx.Flash.Success(ctx.Tr("repo.milestones.create_success", form.Title))
+ ctx.Redirect(ctx.Repo.RepoLink + "/milestones")
+}
+
+// EditMilestone render edting milestone page
+func EditMilestone(ctx *context.Context) {
+ ctx.Data["Title"] = ctx.Tr("repo.milestones.edit")
+ ctx.Data["PageIsMilestones"] = true
+ ctx.Data["PageIsEditMilestone"] = true
+ ctx.Data["RequireDatetimepicker"] = true
+ ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language())
+
+ m, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
+ if err != nil {
+ if models.IsErrMilestoneNotExist(err) {
+ ctx.NotFound("", nil)
+ } else {
+ ctx.ServerError("GetMilestoneByRepoID", err)
+ }
+ return
+ }
+ ctx.Data["title"] = m.Name
+ ctx.Data["content"] = m.Content
+ if len(m.DeadlineString) > 0 {
+ ctx.Data["deadline"] = m.DeadlineString
+ }
+ ctx.HTML(200, tplMilestoneNew)
+}
+
+// EditMilestonePost response for edting milestone
+func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
+ ctx.Data["Title"] = ctx.Tr("repo.milestones.edit")
+ ctx.Data["PageIsMilestones"] = true
+ ctx.Data["PageIsEditMilestone"] = true
+ ctx.Data["RequireDatetimepicker"] = true
+ ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language())
+
+ if ctx.HasError() {
+ ctx.HTML(200, tplMilestoneNew)
+ return
+ }
+
+ if len(form.Deadline) == 0 {
+ form.Deadline = "9999-12-31"
+ }
+ deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local)
+ if err != nil {
+ ctx.Data["Err_Deadline"] = true
+ ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form)
+ return
+ }
+
+ m, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
+ if err != nil {
+ if models.IsErrMilestoneNotExist(err) {
+ ctx.NotFound("", nil)
+ } else {
+ ctx.ServerError("GetMilestoneByRepoID", err)
+ }
+ return
+ }
+ m.Name = form.Title
+ m.Content = form.Content
+ m.DeadlineUnix = util.TimeStamp(deadline.Unix())
+ if err = models.UpdateMilestone(m); err != nil {
+ ctx.ServerError("UpdateMilestone", err)
+ return
+ }
+
+ ctx.Flash.Success(ctx.Tr("repo.milestones.edit_success", m.Name))
+ ctx.Redirect(ctx.Repo.RepoLink + "/milestones")
+}
+
+// ChangeMilestonStatus response for change a milestone's status
+func ChangeMilestonStatus(ctx *context.Context) {
+ m, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
+ if err != nil {
+ if models.IsErrMilestoneNotExist(err) {
+ ctx.NotFound("", err)
+ } else {
+ ctx.ServerError("GetMilestoneByRepoID", err)
+ }
+ return
+ }
+
+ switch ctx.Params(":action") {
+ case "open":
+ if m.IsClosed {
+ if err = models.ChangeMilestoneStatus(m, false); err != nil {
+ ctx.ServerError("ChangeMilestoneStatus", err)
+ return
+ }
+ }
+ ctx.Redirect(ctx.Repo.RepoLink + "/milestones?state=open")
+ case "close":
+ if !m.IsClosed {
+ m.ClosedDateUnix = util.TimeStampNow()
+ if err = models.ChangeMilestoneStatus(m, true); err != nil {
+ ctx.ServerError("ChangeMilestoneStatus", err)
+ return
+ }
+ }
+ ctx.Redirect(ctx.Repo.RepoLink + "/milestones?state=closed")
+ default:
+ ctx.Redirect(ctx.Repo.RepoLink + "/milestones")
+ }
+}
+
+// DeleteMilestone delete a milestone
+func DeleteMilestone(ctx *context.Context) {
+ if err := models.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil {
+ ctx.Flash.Error("DeleteMilestoneByRepoID: " + err.Error())
+ } else {
+ ctx.Flash.Success(ctx.Tr("repo.milestones.deletion_success"))
+ }
+
+ ctx.JSON(200, map[string]interface{}{
+ "redirect": ctx.Repo.RepoLink + "/milestones",
+ })
+}
+
+// MilestoneIssuesAndPulls lists all the issues and pull requests of the milestone
+func MilestoneIssuesAndPulls(ctx *context.Context) {
+ milestoneID := ctx.ParamsInt64(":id")
+ milestone, err := models.GetMilestoneByID(milestoneID)
+ if err != nil {
+ ctx.ServerError("GetMilestoneByID", err)
+ return
+ }
+
+ ctx.Data["Title"] = milestone.Name
+ ctx.Data["Milestone"] = milestone
+
+ issues(ctx, milestoneID, util.OptionalBoolNone)
+
+ ctx.HTML(200, tplMilestoneIssues)
+}