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

project_board.go 6.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright 2020 The Gitea 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 models
  5. import (
  6. "code.gitea.io/gitea/modules/setting"
  7. "code.gitea.io/gitea/modules/timeutil"
  8. "xorm.io/builder"
  9. "xorm.io/xorm"
  10. )
  11. type (
  12. // ProjectBoardType is used to represent a project board type
  13. ProjectBoardType uint8
  14. // ProjectBoardList is a list of all project boards in a repository
  15. ProjectBoardList []*ProjectBoard
  16. )
  17. const (
  18. // ProjectBoardTypeNone is a project board type that has no predefined columns
  19. ProjectBoardTypeNone ProjectBoardType = iota
  20. // ProjectBoardTypeBasicKanban is a project board type that has basic predefined columns
  21. ProjectBoardTypeBasicKanban
  22. // ProjectBoardTypeBugTriage is a project board type that has predefined columns suited to hunting down bugs
  23. ProjectBoardTypeBugTriage
  24. )
  25. // ProjectBoard is used to represent boards on a project
  26. type ProjectBoard struct {
  27. ID int64 `xorm:"pk autoincr"`
  28. Title string
  29. Default bool `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific board will be assigned to this board
  30. ProjectID int64 `xorm:"INDEX NOT NULL"`
  31. CreatorID int64 `xorm:"NOT NULL"`
  32. CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
  33. UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
  34. Issues []*Issue `xorm:"-"`
  35. }
  36. // IsProjectBoardTypeValid checks if the project board type is valid
  37. func IsProjectBoardTypeValid(p ProjectBoardType) bool {
  38. switch p {
  39. case ProjectBoardTypeNone, ProjectBoardTypeBasicKanban, ProjectBoardTypeBugTriage:
  40. return true
  41. default:
  42. return false
  43. }
  44. }
  45. func createBoardsForProjectsType(sess *xorm.Session, project *Project) error {
  46. var items []string
  47. switch project.BoardType {
  48. case ProjectBoardTypeBugTriage:
  49. items = setting.Project.ProjectBoardBugTriageType
  50. case ProjectBoardTypeBasicKanban:
  51. items = setting.Project.ProjectBoardBasicKanbanType
  52. case ProjectBoardTypeNone:
  53. fallthrough
  54. default:
  55. return nil
  56. }
  57. if len(items) == 0 {
  58. return nil
  59. }
  60. var boards = make([]ProjectBoard, 0, len(items))
  61. for _, v := range items {
  62. boards = append(boards, ProjectBoard{
  63. CreatedUnix: timeutil.TimeStampNow(),
  64. CreatorID: project.CreatorID,
  65. Title: v,
  66. ProjectID: project.ID,
  67. })
  68. }
  69. _, err := sess.Insert(boards)
  70. return err
  71. }
  72. // NewProjectBoard adds a new project board to a given project
  73. func NewProjectBoard(board *ProjectBoard) error {
  74. _, err := x.Insert(board)
  75. return err
  76. }
  77. // DeleteProjectBoardByID removes all issues references to the project board.
  78. func DeleteProjectBoardByID(boardID int64) error {
  79. sess := x.NewSession()
  80. defer sess.Close()
  81. if err := sess.Begin(); err != nil {
  82. return err
  83. }
  84. if err := deleteProjectBoardByID(sess, boardID); err != nil {
  85. return err
  86. }
  87. return sess.Commit()
  88. }
  89. func deleteProjectBoardByID(e Engine, boardID int64) error {
  90. board, err := getProjectBoard(e, boardID)
  91. if err != nil {
  92. if IsErrProjectBoardNotExist(err) {
  93. return nil
  94. }
  95. return err
  96. }
  97. if err = board.removeIssues(e); err != nil {
  98. return err
  99. }
  100. if _, err := e.ID(board.ID).Delete(board); err != nil {
  101. return err
  102. }
  103. return nil
  104. }
  105. func deleteProjectBoardByProjectID(e Engine, projectID int64) error {
  106. _, err := e.Where("project_id=?", projectID).Delete(&ProjectBoard{})
  107. return err
  108. }
  109. // GetProjectBoard fetches the current board of a project
  110. func GetProjectBoard(boardID int64) (*ProjectBoard, error) {
  111. return getProjectBoard(x, boardID)
  112. }
  113. func getProjectBoard(e Engine, boardID int64) (*ProjectBoard, error) {
  114. board := new(ProjectBoard)
  115. has, err := e.ID(boardID).Get(board)
  116. if err != nil {
  117. return nil, err
  118. } else if !has {
  119. return nil, ErrProjectBoardNotExist{BoardID: boardID}
  120. }
  121. return board, nil
  122. }
  123. // UpdateProjectBoard updates the title of a project board
  124. func UpdateProjectBoard(board *ProjectBoard) error {
  125. return updateProjectBoard(x, board)
  126. }
  127. func updateProjectBoard(e Engine, board *ProjectBoard) error {
  128. _, err := e.ID(board.ID).Cols(
  129. "title",
  130. ).Update(board)
  131. return err
  132. }
  133. // GetProjectBoards fetches all boards related to a project
  134. // if no default board set, first board is a temporary "Uncategorized" board
  135. func GetProjectBoards(projectID int64) (ProjectBoardList, error) {
  136. return getProjectBoards(x, projectID)
  137. }
  138. func getProjectBoards(e Engine, projectID int64) ([]*ProjectBoard, error) {
  139. var boards = make([]*ProjectBoard, 0, 5)
  140. if err := e.Where("project_id=? AND `default`=?", projectID, false).Find(&boards); err != nil {
  141. return nil, err
  142. }
  143. defaultB, err := getDefaultBoard(e, projectID)
  144. if err != nil {
  145. return nil, err
  146. }
  147. return append([]*ProjectBoard{defaultB}, boards...), nil
  148. }
  149. // getDefaultBoard return default board and create a dummy if none exist
  150. func getDefaultBoard(e Engine, projectID int64) (*ProjectBoard, error) {
  151. var board ProjectBoard
  152. exist, err := e.Where("project_id=? AND `default`=?", projectID, true).Get(&board)
  153. if err != nil {
  154. return nil, err
  155. }
  156. if exist {
  157. return &board, nil
  158. }
  159. // represents a board for issues not assigned to one
  160. return &ProjectBoard{
  161. ProjectID: projectID,
  162. Title: "Uncategorized",
  163. Default: true,
  164. }, nil
  165. }
  166. // SetDefaultBoard represents a board for issues not assigned to one
  167. // if boardID is 0 unset default
  168. func SetDefaultBoard(projectID, boardID int64) error {
  169. sess := x
  170. _, err := sess.Where(builder.Eq{
  171. "project_id": projectID,
  172. "`default`": true,
  173. }).Cols("`default`").Update(&ProjectBoard{Default: false})
  174. if err != nil {
  175. return err
  176. }
  177. if boardID > 0 {
  178. _, err = sess.ID(boardID).Where(builder.Eq{"project_id": projectID}).
  179. Cols("`default`").Update(&ProjectBoard{Default: true})
  180. }
  181. return err
  182. }
  183. // LoadIssues load issues assigned to this board
  184. func (b *ProjectBoard) LoadIssues() (IssueList, error) {
  185. issueList := make([]*Issue, 0, 10)
  186. if b.ID != 0 {
  187. issues, err := Issues(&IssuesOptions{
  188. ProjectBoardID: b.ID,
  189. ProjectID: b.ProjectID,
  190. })
  191. if err != nil {
  192. return nil, err
  193. }
  194. issueList = issues
  195. }
  196. if b.Default {
  197. issues, err := Issues(&IssuesOptions{
  198. ProjectBoardID: -1, // Issues without ProjectBoardID
  199. ProjectID: b.ProjectID,
  200. })
  201. if err != nil {
  202. return nil, err
  203. }
  204. issueList = append(issueList, issues...)
  205. }
  206. b.Issues = issueList
  207. return issueList, nil
  208. }
  209. // LoadIssues load issues assigned to the boards
  210. func (bs ProjectBoardList) LoadIssues() (IssueList, error) {
  211. issues := make(IssueList, 0, len(bs)*10)
  212. for i := range bs {
  213. il, err := bs[i].LoadIssues()
  214. if err != nil {
  215. return nil, err
  216. }
  217. bs[i].Issues = il
  218. issues = append(issues, il...)
  219. }
  220. return issues, nil
  221. }