Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.5 KiB
135 lines
3.5 KiB
3 years ago
|
// Copyright 2018-2022 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/models/db"
|
||
|
user_model "code.gitea.io/gitea/models/user"
|
||
|
"code.gitea.io/gitea/modules/timeutil"
|
||
|
)
|
||
|
|
||
|
// IssueParent represents an issue parent
|
||
|
type IssueParent struct {
|
||
|
ID int64 `xorm:"pk autoincr"`
|
||
|
UserID int64 `xorm:"NOT NULL"`
|
||
|
IssueID int64 `xorm:"UNIQUE(issue_parent) NOT NULL"`
|
||
|
ParentID int64 `xorm:"UNIQUE(issue_parent) NOT NULL"`
|
||
|
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
||
|
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
db.RegisterModel(new(IssueParent))
|
||
|
}
|
||
|
|
||
|
// ParentType Defines Parent Type Constants
|
||
|
type ParentType int
|
||
|
|
||
|
// Define Parent Types
|
||
|
const (
|
||
|
ParentTypeFather ParentType = iota
|
||
|
ParentTypeChild
|
||
|
)
|
||
|
|
||
|
// CreateIssueParent creates a new parent for an issue
|
||
|
func CreateIssueParent(user *user_model.User, issue, parent *Issue) error {
|
||
|
ctx, committer, err := db.TxContext()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer committer.Close()
|
||
|
sess := db.GetEngine(ctx)
|
||
|
|
||
|
// Check if it aleready exists
|
||
|
exists, err := issueParentExists(sess, issue.ID, parent.ID)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if exists {
|
||
|
return ErrParentExists{issue.ID, parent.ID}
|
||
|
}
|
||
|
// And if it would be circular
|
||
|
circular, err := issueParentExists(sess, parent.ID, issue.ID)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if circular {
|
||
|
return ErrCircularParent{issue.ID, parent.ID}
|
||
|
}
|
||
|
|
||
|
if err := db.Insert(ctx, &IssueParent{
|
||
|
UserID: user.ID,
|
||
|
IssueID: issue.ID,
|
||
|
ParentID: parent.ID,
|
||
|
}); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Add comment referencing the new parent
|
||
|
if err = createIssueParentComment(ctx, user, issue, parent, true); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return committer.Commit()
|
||
|
}
|
||
|
|
||
|
// RemoveIssueParent removes a parent from an issue
|
||
|
func RemoveIssueParent(user *user_model.User, issue, parent *Issue, parentType ParentType) (err error) {
|
||
|
ctx, committer, err := db.TxContext()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer committer.Close()
|
||
|
|
||
|
var issueParentToDelete IssueParent
|
||
|
|
||
|
switch parentType {
|
||
|
case ParentTypeFather:
|
||
|
issueParentToDelete = IssueParent{IssueID: issue.ID, ParentID: parent.ID}
|
||
|
case ParentTypeChild:
|
||
|
issueParentToDelete = IssueParent{IssueID: parent.ID, ParentID: issue.ID}
|
||
|
default:
|
||
|
return ErrUnknownParentType{parentType}
|
||
|
}
|
||
|
|
||
|
affected, err := db.GetEngine(ctx).Delete(&issueParentToDelete)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// If we deleted nothing, the parent did not exist
|
||
|
if affected <= 0 {
|
||
|
return ErrParentNotExists{issue.ID, parent.ID}
|
||
|
}
|
||
|
|
||
|
// Add comment referencing the removed parent
|
||
|
if err = createIssueParentComment(ctx, user, issue, parent, false); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return committer.Commit()
|
||
|
}
|
||
|
|
||
|
// Check if the parent already exists
|
||
|
func issueParentExists(e db.Engine, issueID, depID int64) (bool, error) {
|
||
|
return e.Where("(issue_id = ? AND parent_id = ?)", issueID, depID).Exist(&IssueParent{})
|
||
|
}
|
||
|
|
||
|
// IssueNoParentsLeft checks if issue can be closed
|
||
|
func IssueNoParentsLeft(issue *Issue) (bool, error) {
|
||
|
return issueNoParentsLeft(db.GetEngine(db.DefaultContext), issue)
|
||
|
}
|
||
|
|
||
|
func issueNoParentsLeft(e db.Engine, issue *Issue) (bool, error) {
|
||
|
exists, err := e.
|
||
|
Table("issue_parent").
|
||
|
Select("issue.*").
|
||
|
Join("INNER", "issue", "issue.id = issue_parent.parent_id").
|
||
|
Where("issue_parent.issue_id = ?", issue.ID).
|
||
|
And("issue.is_closed = ?", "0").
|
||
|
Exist(&Issue{})
|
||
|
|
||
|
return !exists, err
|
||
|
}
|