2020-08-17 06:07:38 +03:00
// Copyright 2020 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 models
import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
2021-01-15 23:29:32 +03:00
"xorm.io/builder"
2020-08-17 06:07:38 +03:00
"xorm.io/xorm"
)
type (
// ProjectBoardType is used to represent a project board type
ProjectBoardType uint8
// ProjectBoardList is a list of all project boards in a repository
ProjectBoardList [ ] * ProjectBoard
)
const (
// ProjectBoardTypeNone is a project board type that has no predefined columns
ProjectBoardTypeNone ProjectBoardType = iota
// ProjectBoardTypeBasicKanban is a project board type that has basic predefined columns
ProjectBoardTypeBasicKanban
// ProjectBoardTypeBugTriage is a project board type that has predefined columns suited to hunting down bugs
ProjectBoardTypeBugTriage
)
// ProjectBoard is used to represent boards on a project
type ProjectBoard struct {
ID int64 ` xorm:"pk autoincr" `
Title string
Default bool ` xorm:"NOT NULL DEFAULT false" ` // issues not assigned to a specific board will be assigned to this board
2021-02-12 14:01:26 +03:00
Sorting int8 ` xorm:"NOT NULL DEFAULT 0" `
2020-08-17 06:07:38 +03:00
ProjectID int64 ` xorm:"INDEX NOT NULL" `
CreatorID int64 ` xorm:"NOT NULL" `
CreatedUnix timeutil . TimeStamp ` xorm:"INDEX created" `
UpdatedUnix timeutil . TimeStamp ` xorm:"INDEX updated" `
Issues [ ] * Issue ` xorm:"-" `
}
// IsProjectBoardTypeValid checks if the project board type is valid
func IsProjectBoardTypeValid ( p ProjectBoardType ) bool {
switch p {
case ProjectBoardTypeNone , ProjectBoardTypeBasicKanban , ProjectBoardTypeBugTriage :
return true
default :
return false
}
}
func createBoardsForProjectsType ( sess * xorm . Session , project * Project ) error {
var items [ ] string
switch project . BoardType {
case ProjectBoardTypeBugTriage :
items = setting . Project . ProjectBoardBugTriageType
case ProjectBoardTypeBasicKanban :
items = setting . Project . ProjectBoardBasicKanbanType
case ProjectBoardTypeNone :
fallthrough
default :
return nil
}
if len ( items ) == 0 {
return nil
}
2021-03-14 21:52:12 +03:00
boards := make ( [ ] ProjectBoard , 0 , len ( items ) )
2020-08-17 06:07:38 +03:00
for _ , v := range items {
boards = append ( boards , ProjectBoard {
CreatedUnix : timeutil . TimeStampNow ( ) ,
CreatorID : project . CreatorID ,
Title : v ,
ProjectID : project . ID ,
} )
}
_ , err := sess . Insert ( boards )
return err
}
// NewProjectBoard adds a new project board to a given project
func NewProjectBoard ( board * ProjectBoard ) error {
_ , err := x . Insert ( board )
return err
}
// DeleteProjectBoardByID removes all issues references to the project board.
func DeleteProjectBoardByID ( boardID int64 ) error {
sess := x . NewSession ( )
defer sess . Close ( )
if err := sess . Begin ( ) ; err != nil {
return err
}
if err := deleteProjectBoardByID ( sess , boardID ) ; err != nil {
return err
}
return sess . Commit ( )
}
func deleteProjectBoardByID ( e Engine , boardID int64 ) error {
board , err := getProjectBoard ( e , boardID )
if err != nil {
if IsErrProjectBoardNotExist ( err ) {
return nil
}
return err
}
if err = board . removeIssues ( e ) ; err != nil {
return err
}
if _ , err := e . ID ( board . ID ) . Delete ( board ) ; err != nil {
return err
}
return nil
}
func deleteProjectBoardByProjectID ( e Engine , projectID int64 ) error {
_ , err := e . Where ( "project_id=?" , projectID ) . Delete ( & ProjectBoard { } )
return err
}
// GetProjectBoard fetches the current board of a project
func GetProjectBoard ( boardID int64 ) ( * ProjectBoard , error ) {
return getProjectBoard ( x , boardID )
}
func getProjectBoard ( e Engine , boardID int64 ) ( * ProjectBoard , error ) {
board := new ( ProjectBoard )
has , err := e . ID ( boardID ) . Get ( board )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrProjectBoardNotExist { BoardID : boardID }
}
return board , nil
}
2021-02-11 19:32:27 +03:00
// UpdateProjectBoard updates a project board
2020-08-17 06:07:38 +03:00
func UpdateProjectBoard ( board * ProjectBoard ) error {
return updateProjectBoard ( x , board )
}
func updateProjectBoard ( e Engine , board * ProjectBoard ) error {
2021-02-11 19:32:27 +03:00
var fieldToUpdate [ ] string
if board . Sorting != 0 {
fieldToUpdate = append ( fieldToUpdate , "sorting" )
}
if board . Title != "" {
fieldToUpdate = append ( fieldToUpdate , "title" )
}
_ , err := e . ID ( board . ID ) . Cols ( fieldToUpdate ... ) . Update ( board )
2020-08-17 06:07:38 +03:00
return err
}
// GetProjectBoards fetches all boards related to a project
2021-01-15 23:29:32 +03:00
// if no default board set, first board is a temporary "Uncategorized" board
func GetProjectBoards ( projectID int64 ) ( ProjectBoardList , error ) {
return getProjectBoards ( x , projectID )
}
2020-08-17 06:07:38 +03:00
2021-01-15 23:29:32 +03:00
func getProjectBoards ( e Engine , projectID int64 ) ( [ ] * ProjectBoard , error ) {
2021-03-14 21:52:12 +03:00
boards := make ( [ ] * ProjectBoard , 0 , 5 )
2020-08-17 06:07:38 +03:00
2021-02-11 19:32:27 +03:00
if err := e . Where ( "project_id=? AND `default`=?" , projectID , false ) . OrderBy ( "Sorting" ) . Find ( & boards ) ; err != nil {
2021-01-15 23:29:32 +03:00
return nil , err
}
defaultB , err := getDefaultBoard ( e , projectID )
if err != nil {
return nil , err
}
return append ( [ ] * ProjectBoard { defaultB } , boards ... ) , nil
2020-08-17 06:07:38 +03:00
}
2021-01-15 23:29:32 +03:00
// getDefaultBoard return default board and create a dummy if none exist
func getDefaultBoard ( e Engine , projectID int64 ) ( * ProjectBoard , error ) {
var board ProjectBoard
exist , err := e . Where ( "project_id=? AND `default`=?" , projectID , true ) . Get ( & board )
if err != nil {
return nil , err
}
if exist {
return & board , nil
}
// represents a board for issues not assigned to one
2020-08-17 06:07:38 +03:00
return & ProjectBoard {
ProjectID : projectID ,
Title : "Uncategorized" ,
Default : true ,
} , nil
}
2021-01-15 23:29:32 +03:00
// SetDefaultBoard represents a board for issues not assigned to one
// if boardID is 0 unset default
func SetDefaultBoard ( projectID , boardID int64 ) error {
sess := x
_ , err := sess . Where ( builder . Eq {
"project_id" : projectID ,
"`default`" : true ,
} ) . Cols ( "`default`" ) . Update ( & ProjectBoard { Default : false } )
if err != nil {
return err
}
if boardID > 0 {
_ , err = sess . ID ( boardID ) . Where ( builder . Eq { "project_id" : projectID } ) .
Cols ( "`default`" ) . Update ( & ProjectBoard { Default : true } )
}
return err
}
2020-08-17 06:07:38 +03:00
// LoadIssues load issues assigned to this board
func ( b * ProjectBoard ) LoadIssues ( ) ( IssueList , error ) {
2021-01-15 23:29:32 +03:00
issueList := make ( [ ] * Issue , 0 , 10 )
if b . ID != 0 {
issues , err := Issues ( & IssuesOptions {
ProjectBoardID : b . ID ,
ProjectID : b . ProjectID ,
} )
if err != nil {
return nil , err
}
issueList = issues
}
if b . Default {
issues , err := Issues ( & IssuesOptions {
ProjectBoardID : - 1 , // Issues without ProjectBoardID
ProjectID : b . ProjectID ,
} )
if err != nil {
return nil , err
}
issueList = append ( issueList , issues ... )
}
2021-01-20 22:53:48 +03:00
if err := IssueList ( issueList ) . LoadComments ( ) ; err != nil {
return nil , err
}
2021-01-15 23:29:32 +03:00
b . Issues = issueList
return issueList , nil
2020-08-17 06:07:38 +03:00
}
// LoadIssues load issues assigned to the boards
func ( bs ProjectBoardList ) LoadIssues ( ) ( IssueList , error ) {
issues := make ( IssueList , 0 , len ( bs ) * 10 )
for i := range bs {
il , err := bs [ i ] . LoadIssues ( )
if err != nil {
return nil , err
}
bs [ i ] . Issues = il
issues = append ( issues , il ... )
}
return issues , nil
}
2021-02-11 19:32:27 +03:00
// UpdateProjectBoardSorting update project board sorting
func UpdateProjectBoardSorting ( bs ProjectBoardList ) error {
for i := range bs {
_ , err := x . ID ( bs [ i ] . ID ) . Cols (
"sorting" ,
) . Update ( bs [ i ] )
if err != nil {
return err
}
}
return nil
}