2018-07-18 00:23:58 +03:00
// Copyright 2018 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 (
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2019-08-15 17:46:21 +03:00
"code.gitea.io/gitea/modules/timeutil"
2018-07-18 00:23:58 +03:00
)
// IssueDependency represents an issue dependency
type IssueDependency struct {
2019-08-15 17:46:21 +03:00
ID int64 ` xorm:"pk autoincr" `
UserID int64 ` xorm:"NOT NULL" `
IssueID int64 ` xorm:"UNIQUE(issue_dependency) NOT NULL" `
DependencyID int64 ` xorm:"UNIQUE(issue_dependency) NOT NULL" `
CreatedUnix timeutil . TimeStamp ` xorm:"created" `
UpdatedUnix timeutil . TimeStamp ` xorm:"updated" `
2018-07-18 00:23:58 +03:00
}
2021-09-19 14:49:59 +03:00
func init ( ) {
db . RegisterModel ( new ( IssueDependency ) )
}
2018-07-18 00:23:58 +03:00
// DependencyType Defines Dependency Type Constants
type DependencyType int
// Define Dependency Types
const (
DependencyTypeBlockedBy DependencyType = iota
DependencyTypeBlocking
)
// CreateIssueDependency creates a new dependency for an issue
2021-11-24 12:49:20 +03:00
func CreateIssueDependency ( user * user_model . User , issue , dep * Issue ) error {
2021-11-19 16:39:57 +03:00
ctx , committer , err := db . TxContext ( )
if err != nil {
2018-07-18 00:23:58 +03:00
return err
}
2021-11-19 16:39:57 +03:00
defer committer . Close ( )
sess := db . GetEngine ( ctx )
2018-07-18 00:23:58 +03:00
// Check if it aleready exists
exists , err := issueDepExists ( sess , issue . ID , dep . ID )
if err != nil {
return err
}
if exists {
return ErrDependencyExists { issue . ID , dep . ID }
}
// And if it would be circular
circular , err := issueDepExists ( sess , dep . ID , issue . ID )
if err != nil {
return err
}
if circular {
return ErrCircularDependency { issue . ID , dep . ID }
}
2021-11-21 18:41:00 +03:00
if err := db . Insert ( ctx , & IssueDependency {
2018-07-18 00:23:58 +03:00
UserID : user . ID ,
IssueID : issue . ID ,
DependencyID : dep . ID ,
} ) ; err != nil {
return err
}
// Add comment referencing the new dependency
2021-11-19 16:39:57 +03:00
if err = createIssueDependencyComment ( ctx , user , issue , dep , true ) ; err != nil {
2018-07-18 00:23:58 +03:00
return err
}
2021-11-19 16:39:57 +03:00
return committer . Commit ( )
2018-07-18 00:23:58 +03:00
}
// RemoveIssueDependency removes a dependency from an issue
2021-11-24 12:49:20 +03:00
func RemoveIssueDependency ( user * user_model . User , issue , dep * Issue , depType DependencyType ) ( err error ) {
2021-11-19 16:39:57 +03:00
ctx , committer , err := db . TxContext ( )
if err != nil {
2018-07-18 00:23:58 +03:00
return err
}
2021-11-19 16:39:57 +03:00
defer committer . Close ( )
2018-07-18 00:23:58 +03:00
var issueDepToDelete IssueDependency
switch depType {
case DependencyTypeBlockedBy :
issueDepToDelete = IssueDependency { IssueID : issue . ID , DependencyID : dep . ID }
case DependencyTypeBlocking :
issueDepToDelete = IssueDependency { IssueID : dep . ID , DependencyID : issue . ID }
default :
return ErrUnknownDependencyType { depType }
}
2021-11-19 16:39:57 +03:00
affected , err := db . GetEngine ( ctx ) . Delete ( & issueDepToDelete )
2018-07-18 00:23:58 +03:00
if err != nil {
return err
}
// If we deleted nothing, the dependency did not exist
if affected <= 0 {
return ErrDependencyNotExists { issue . ID , dep . ID }
}
// Add comment referencing the removed dependency
2021-11-19 16:39:57 +03:00
if err = createIssueDependencyComment ( ctx , user , issue , dep , false ) ; err != nil {
2018-07-18 00:23:58 +03:00
return err
}
2021-11-19 16:39:57 +03:00
return committer . Commit ( )
2018-07-18 00:23:58 +03:00
}
// Check if the dependency already exists
2021-09-19 14:49:59 +03:00
func issueDepExists ( e db . Engine , issueID , depID int64 ) ( bool , error ) {
2018-07-18 00:23:58 +03:00
return e . Where ( "(issue_id = ? AND dependency_id = ?)" , issueID , depID ) . Exist ( & IssueDependency { } )
}
// IssueNoDependenciesLeft checks if issue can be closed
func IssueNoDependenciesLeft ( issue * Issue ) ( bool , error ) {
2021-09-23 18:45:36 +03:00
return issueNoDependenciesLeft ( db . GetEngine ( db . DefaultContext ) , issue )
2018-10-27 17:45:24 +03:00
}
2018-07-18 00:23:58 +03:00
2021-09-19 14:49:59 +03:00
func issueNoDependenciesLeft ( e db . Engine , issue * Issue ) ( bool , error ) {
2018-10-27 17:45:24 +03:00
exists , err := e .
2018-07-18 00:23:58 +03:00
Table ( "issue_dependency" ) .
Select ( "issue.*" ) .
Join ( "INNER" , "issue" , "issue.id = issue_dependency.dependency_id" ) .
Where ( "issue_dependency.issue_id = ?" , issue . ID ) .
And ( "issue.is_closed = ?" , "0" ) .
Exist ( & Issue { } )
return ! exists , err
}