2022-03-29 22:16:31 +08:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2022-03-29 22:16:31 +08:00
package project
import (
"context"
"fmt"
"code.gitea.io/gitea/models/db"
2022-06-16 04:51:34 +02:00
"code.gitea.io/gitea/modules/log"
2024-05-08 21:44:57 +08:00
"code.gitea.io/gitea/modules/util"
2022-03-29 22:16:31 +08:00
)
// ProjectIssue saves relation from issue to a project
type ProjectIssue struct { //revive:disable-line:exported
ID int64 ` xorm:"pk autoincr" `
IssueID int64 ` xorm:"INDEX" `
ProjectID int64 ` xorm:"INDEX" `
2024-05-27 16:59:54 +08:00
// ProjectColumnID should not be zero since 1.22. If it's zero, the issue will not be displayed on UI and it might result in errors.
ProjectColumnID int64 ` xorm:"'project_board_id' INDEX" `
2022-05-06 22:25:59 +08:00
2024-05-27 16:59:54 +08:00
// the sorting order on the column
2022-05-06 22:25:59 +08:00
Sorting int64 ` xorm:"NOT NULL DEFAULT 0" `
2022-03-29 22:16:31 +08:00
}
func init ( ) {
db . RegisterModel ( new ( ProjectIssue ) )
}
2022-05-20 22:08:52 +08:00
func deleteProjectIssuesByProjectID ( ctx context . Context , projectID int64 ) error {
_ , err := db . GetEngine ( ctx ) . Where ( "project_id=?" , projectID ) . Delete ( & ProjectIssue { } )
2022-03-29 22:16:31 +08:00
return err
}
// NumIssues return counter of all issues assigned to a project
2023-09-29 14:12:54 +02:00
func ( p * Project ) NumIssues ( ctx context . Context ) int {
c , err := db . GetEngine ( ctx ) . Table ( "project_issue" ) .
2022-03-29 22:16:31 +08:00
Where ( "project_id=?" , p . ID ) .
GroupBy ( "issue_id" ) .
Cols ( "issue_id" ) .
Count ( )
if err != nil {
2022-06-16 04:51:34 +02:00
log . Error ( "NumIssues: %v" , err )
2022-03-29 22:16:31 +08:00
return 0
}
return int ( c )
}
// NumClosedIssues return counter of closed issues assigned to a project
2023-09-29 14:12:54 +02:00
func ( p * Project ) NumClosedIssues ( ctx context . Context ) int {
c , err := db . GetEngine ( ctx ) . Table ( "project_issue" ) .
2022-03-29 22:16:31 +08:00
Join ( "INNER" , "issue" , "project_issue.issue_id=issue.id" ) .
Where ( "project_issue.project_id=? AND issue.is_closed=?" , p . ID , true ) .
Cols ( "issue_id" ) .
Count ( )
if err != nil {
2022-06-16 04:51:34 +02:00
log . Error ( "NumClosedIssues: %v" , err )
2022-03-29 22:16:31 +08:00
return 0
}
return int ( c )
}
// NumOpenIssues return counter of open issues assigned to a project
2023-09-29 14:12:54 +02:00
func ( p * Project ) NumOpenIssues ( ctx context . Context ) int {
c , err := db . GetEngine ( ctx ) . Table ( "project_issue" ) .
2022-03-29 22:16:31 +08:00
Join ( "INNER" , "issue" , "project_issue.issue_id=issue.id" ) .
2022-06-16 04:51:34 +02:00
Where ( "project_issue.project_id=? AND issue.is_closed=?" , p . ID , false ) .
Cols ( "issue_id" ) .
Count ( )
2022-03-29 22:16:31 +08:00
if err != nil {
2022-06-16 04:51:34 +02:00
log . Error ( "NumOpenIssues: %v" , err )
2022-03-29 22:16:31 +08:00
return 0
}
return int ( c )
}
2024-05-27 16:59:54 +08:00
func ( c * Column ) moveIssuesToAnotherColumn ( ctx context . Context , newColumn * Column ) error {
if c . ProjectID != newColumn . ProjectID {
2024-05-08 21:44:57 +08:00
return fmt . Errorf ( "columns have to be in the same project" )
}
2024-05-27 16:59:54 +08:00
if c . ID == newColumn . ID {
2024-05-08 21:44:57 +08:00
return nil
}
res := struct {
MaxSorting int64
IssueCount int64
} { }
if _ , err := db . GetEngine ( ctx ) . Select ( "max(sorting) as max_sorting, count(*) as issue_count" ) .
Table ( "project_issue" ) .
Where ( "project_id=?" , newColumn . ProjectID ) .
And ( "project_board_id=?" , newColumn . ID ) .
Get ( & res ) ; err != nil {
return err
}
2024-05-27 16:59:54 +08:00
issues , err := c . GetIssues ( ctx )
2024-05-08 21:44:57 +08:00
if err != nil {
return err
}
if len ( issues ) == 0 {
return nil
}
nextSorting := util . Iif ( res . IssueCount > 0 , res . MaxSorting + 1 , 0 )
return db . WithTx ( ctx , func ( ctx context . Context ) error {
for i , issue := range issues {
2024-05-27 16:59:54 +08:00
issue . ProjectColumnID = newColumn . ID
2024-05-08 21:44:57 +08:00
issue . Sorting = nextSorting + int64 ( i )
if _ , err := db . GetEngine ( ctx ) . ID ( issue . ID ) . Cols ( "project_board_id" , "sorting" ) . Update ( issue ) ; err != nil {
return err
}
}
return nil
} )
2022-03-29 22:16:31 +08:00
}
2024-08-13 05:53:43 +03:00
// DeleteAllProjectIssueByIssueIDsAndProjectIDs delete all project's issues by issue's and project's ids
func DeleteAllProjectIssueByIssueIDsAndProjectIDs ( ctx context . Context , issueIDs , projectIDs [ ] int64 ) error {
_ , err := db . GetEngine ( ctx ) . In ( "project_id" , projectIDs ) . In ( "issue_id" , issueIDs ) . Delete ( & ProjectIssue { } )
return err
}