Платформа ЦРНП "Мирокод" для разработки проектов 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

// 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
}