mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-25 03:22:36 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			303 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			303 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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"
 | |
| 
 | |
| 	"xorm.io/builder"
 | |
| 	"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
 | |
| 	Sorting int8 `xorm:"DEFAULT 0"`
 | |
| 
 | |
| 	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
 | |
| 	}
 | |
| 
 | |
| 	var boards = make([]ProjectBoard, 0, len(items))
 | |
| 
 | |
| 	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
 | |
| }
 | |
| 
 | |
| // UpdateProjectBoard updates a project board
 | |
| func UpdateProjectBoard(board *ProjectBoard) error {
 | |
| 	return updateProjectBoard(x, board)
 | |
| }
 | |
| 
 | |
| func updateProjectBoard(e Engine, board *ProjectBoard) error {
 | |
| 	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)
 | |
| 
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // GetProjectBoards fetches all boards related to a project
 | |
| // if no default board set, first board is a temporary "Uncategorized" board
 | |
| func GetProjectBoards(projectID int64) (ProjectBoardList, error) {
 | |
| 	return getProjectBoards(x, projectID)
 | |
| }
 | |
| 
 | |
| func getProjectBoards(e Engine, projectID int64) ([]*ProjectBoard, error) {
 | |
| 	var boards = make([]*ProjectBoard, 0, 5)
 | |
| 
 | |
| 	if err := e.Where("project_id=? AND `default`=?", projectID, false).OrderBy("Sorting").Find(&boards); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	defaultB, err := getDefaultBoard(e, projectID)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return append([]*ProjectBoard{defaultB}, boards...), nil
 | |
| }
 | |
| 
 | |
| // 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
 | |
| 	return &ProjectBoard{
 | |
| 		ProjectID: projectID,
 | |
| 		Title:     "Uncategorized",
 | |
| 		Default:   true,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // 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
 | |
| }
 | |
| 
 | |
| // LoadIssues load issues assigned to this board
 | |
| func (b *ProjectBoard) LoadIssues() (IssueList, error) {
 | |
| 	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...)
 | |
| 	}
 | |
| 
 | |
| 	if err := IssueList(issueList).LoadComments(); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	b.Issues = issueList
 | |
| 	return issueList, nil
 | |
| }
 | |
| 
 | |
| // 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
 | |
| }
 | |
| 
 | |
| // 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
 | |
| }
 |