You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
8.5 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package repo
  5. import (
  6. "fmt"
  7. "net/url"
  8. "strings"
  9. "github.com/Unknwon/com"
  10. "github.com/go-martini/martini"
  11. "github.com/gogits/gogs/models"
  12. "github.com/gogits/gogs/modules/auth"
  13. "github.com/gogits/gogs/modules/base"
  14. "github.com/gogits/gogs/modules/log"
  15. "github.com/gogits/gogs/modules/mailer"
  16. "github.com/gogits/gogs/modules/middleware"
  17. )
  18. func Issues(ctx *middleware.Context) {
  19. ctx.Data["Title"] = "Issues"
  20. ctx.Data["IsRepoToolbarIssues"] = true
  21. ctx.Data["IsRepoToolbarIssuesList"] = true
  22. ctx.Data["ViewType"] = "all"
  23. milestoneId, _ := base.StrTo(ctx.Query("milestone")).Int()
  24. page, _ := base.StrTo(ctx.Query("page")).Int()
  25. ctx.Data["IssueCreatedCount"] = 0
  26. var posterId int64 = 0
  27. isCreatedBy := ctx.Query("type") == "created_by"
  28. if isCreatedBy {
  29. if !ctx.IsSigned {
  30. ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI))
  31. ctx.Redirect("/user/login/", 302)
  32. return
  33. }
  34. ctx.Data["ViewType"] = "created_by"
  35. }
  36. // Get issues.
  37. issues, err := models.GetIssues(0, ctx.Repo.Repository.Id, posterId, int64(milestoneId), page,
  38. ctx.Query("state") == "closed", false, ctx.Query("labels"), ctx.Query("sortType"))
  39. if err != nil {
  40. ctx.Handle(200, "issue.Issues: %v", err)
  41. return
  42. }
  43. if ctx.IsSigned {
  44. posterId = ctx.User.Id
  45. }
  46. var createdByCount int
  47. showIssues := make([]models.Issue, 0, len(issues))
  48. // Get posters.
  49. for i := range issues {
  50. u, err := models.GetUserById(issues[i].PosterId)
  51. if err != nil {
  52. ctx.Handle(200, "issue.Issues(get poster): %v", err)
  53. return
  54. }
  55. if isCreatedBy && u.Id != posterId {
  56. continue
  57. }
  58. if u.Id == posterId {
  59. createdByCount++
  60. }
  61. issues[i].Poster = u
  62. showIssues = append(showIssues, issues[i])
  63. }
  64. ctx.Data["Issues"] = showIssues
  65. ctx.Data["IssueCount"] = ctx.Repo.Repository.NumIssues
  66. ctx.Data["OpenCount"] = ctx.Repo.Repository.NumOpenIssues
  67. ctx.Data["ClosedCount"] = ctx.Repo.Repository.NumClosedIssues
  68. ctx.Data["IssueCreatedCount"] = createdByCount
  69. ctx.Data["IsShowClosed"] = ctx.Query("state") == "closed"
  70. ctx.HTML(200, "issue/list")
  71. }
  72. func CreateIssue(ctx *middleware.Context, params martini.Params) {
  73. ctx.Data["Title"] = "Create issue"
  74. ctx.Data["IsRepoToolbarIssues"] = true
  75. ctx.Data["IsRepoToolbarIssuesList"] = false
  76. ctx.HTML(200, "issue/create")
  77. }
  78. func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
  79. ctx.Data["Title"] = "Create issue"
  80. ctx.Data["IsRepoToolbarIssues"] = true
  81. ctx.Data["IsRepoToolbarIssuesList"] = false
  82. if ctx.HasError() {
  83. ctx.HTML(200, "issue/create")
  84. return
  85. }
  86. issue, err := models.CreateIssue(ctx.User.Id, ctx.Repo.Repository.Id, form.MilestoneId, form.AssigneeId,
  87. ctx.Repo.Repository.NumIssues, form.IssueName, form.Labels, form.Content, false)
  88. if err != nil {
  89. ctx.Handle(500, "issue.CreateIssue(CreateIssue)", err)
  90. return
  91. }
  92. // Notify watchers.
  93. if err = models.NotifyWatchers(&models.Action{ActUserId: ctx.User.Id, ActUserName: ctx.User.Name, ActEmail: ctx.User.Email,
  94. OpType: models.OP_CREATE_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
  95. RepoId: ctx.Repo.Repository.Id, RepoName: ctx.Repo.Repository.Name, RefName: ""}); err != nil {
  96. ctx.Handle(500, "issue.CreateIssue(NotifyWatchers)", err)
  97. return
  98. }
  99. // Mail watchers and mentions.
  100. if base.Service.NotifyMail {
  101. tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
  102. if err != nil {
  103. ctx.Handle(500, "issue.CreateIssue(SendIssueNotifyMail)", err)
  104. return
  105. }
  106. tos = append(tos, ctx.User.LowerName)
  107. ms := base.MentionPattern.FindAllString(issue.Content, -1)
  108. newTos := make([]string, 0, len(ms))
  109. for _, m := range ms {
  110. if com.IsSliceContainsStr(tos, m[1:]) {
  111. continue
  112. }
  113. newTos = append(newTos, m[1:])
  114. }
  115. if err = mailer.SendIssueMentionMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository,
  116. issue, models.GetUserEmailsByNames(newTos)); err != nil {
  117. ctx.Handle(500, "issue.CreateIssue(SendIssueMentionMail)", err)
  118. return
  119. }
  120. }
  121. log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id)
  122. ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index))
  123. }
  124. func ViewIssue(ctx *middleware.Context, params martini.Params) {
  125. index, err := base.StrTo(params["index"]).Int()
  126. if err != nil {
  127. ctx.Handle(404, "issue.ViewIssue", err)
  128. return
  129. }
  130. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(index))
  131. if err != nil {
  132. if err == models.ErrIssueNotExist {
  133. ctx.Handle(404, "issue.ViewIssue", err)
  134. } else {
  135. ctx.Handle(200, "issue.ViewIssue", err)
  136. }
  137. return
  138. }
  139. // Get posters.
  140. u, err := models.GetUserById(issue.PosterId)
  141. if err != nil {
  142. ctx.Handle(200, "issue.ViewIssue(get poster): %v", err)
  143. return
  144. }
  145. issue.Poster = u
  146. issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
  147. // Get comments.
  148. comments, err := models.GetIssueComments(issue.Id)
  149. if err != nil {
  150. ctx.Handle(200, "issue.ViewIssue(get comments): %v", err)
  151. return
  152. }
  153. // Get posters.
  154. for i := range comments {
  155. u, err := models.GetUserById(comments[i].PosterId)
  156. if err != nil {
  157. ctx.Handle(200, "issue.ViewIssue(get poster): %v", err)
  158. return
  159. }
  160. comments[i].Poster = u
  161. comments[i].Content = string(base.RenderMarkdown([]byte(comments[i].Content), ctx.Repo.RepoLink))
  162. }
  163. ctx.Data["Title"] = issue.Name
  164. ctx.Data["Issue"] = issue
  165. ctx.Data["Comments"] = comments
  166. ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || (ctx.IsSigned && issue.PosterId == ctx.User.Id)
  167. ctx.Data["IsRepoToolbarIssues"] = true
  168. ctx.Data["IsRepoToolbarIssuesList"] = false
  169. ctx.HTML(200, "issue/view")
  170. }
  171. func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
  172. index, err := base.StrTo(params["index"]).Int()
  173. if err != nil {
  174. ctx.Handle(404, "issue.UpdateIssue", err)
  175. return
  176. }
  177. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(index))
  178. if err != nil {
  179. if err == models.ErrIssueNotExist {
  180. ctx.Handle(404, "issue.UpdateIssue", err)
  181. } else {
  182. ctx.Handle(200, "issue.UpdateIssue(get issue)", err)
  183. }
  184. return
  185. }
  186. if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner {
  187. ctx.Handle(404, "issue.UpdateIssue", nil)
  188. return
  189. }
  190. issue.Name = form.IssueName
  191. issue.MilestoneId = form.MilestoneId
  192. issue.AssigneeId = form.AssigneeId
  193. issue.Labels = form.Labels
  194. issue.Content = form.Content
  195. if err = models.UpdateIssue(issue); err != nil {
  196. ctx.Handle(200, "issue.UpdateIssue(update issue)", err)
  197. return
  198. }
  199. ctx.JSON(200, map[string]interface{}{
  200. "ok": true,
  201. "title": issue.Name,
  202. "content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink)),
  203. })
  204. }
  205. func Comment(ctx *middleware.Context, params martini.Params) {
  206. index, err := base.StrTo(ctx.Query("issueIndex")).Int64()
  207. if err != nil {
  208. ctx.Handle(404, "issue.Comment(get index)", err)
  209. return
  210. }
  211. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
  212. if err != nil {
  213. if err == models.ErrIssueNotExist {
  214. ctx.Handle(404, "issue.Comment", err)
  215. } else {
  216. ctx.Handle(200, "issue.Comment(get issue)", err)
  217. }
  218. return
  219. }
  220. // Check if issue owner changes the status of issue.
  221. var newStatus string
  222. if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
  223. newStatus = ctx.Query("change_status")
  224. }
  225. if len(newStatus) > 0 {
  226. if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) ||
  227. (strings.Contains(newStatus, "Close") && !issue.IsClosed) {
  228. issue.IsClosed = !issue.IsClosed
  229. if err = models.UpdateIssue(issue); err != nil {
  230. ctx.Handle(200, "issue.Comment(update issue status)", err)
  231. return
  232. }
  233. cmtType := models.IT_CLOSE
  234. if !issue.IsClosed {
  235. cmtType = models.IT_REOPEN
  236. }
  237. if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, ""); err != nil {
  238. ctx.Handle(200, "issue.Comment(create status change comment)", err)
  239. return
  240. }
  241. log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed)
  242. }
  243. }
  244. content := ctx.Query("content")
  245. if len(content) > 0 {
  246. switch params["action"] {
  247. case "new":
  248. if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.IT_PLAIN, content); err != nil {
  249. ctx.Handle(500, "issue.Comment(create comment)", err)
  250. return
  251. }
  252. log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
  253. default:
  254. ctx.Handle(404, "issue.Comment", err)
  255. return
  256. }
  257. }
  258. ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index))
  259. }