diff options
Diffstat (limited to 'models/issue.go')
-rw-r--r-- | models/issue.go | 406 |
1 files changed, 233 insertions, 173 deletions
diff --git a/models/issue.go b/models/issue.go index 2b80e576..d423f056 100644 --- a/models/issue.go +++ b/models/issue.go @@ -17,12 +17,12 @@ import ( "github.com/go-xorm/xorm" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/setting" ) var ( ErrIssueNotExist = errors.New("Issue does not exist") ErrLabelNotExist = errors.New("Label does not exist") - ErrMilestoneNotExist = errors.New("Milestone does not exist") ErrWrongIssueCounter = errors.New("Invalid number of issues for this milestone") ErrAttachmentNotExist = errors.New("Attachment does not exist") ErrAttachmentNotLinked = errors.New("Attachment does not belong to this issue") @@ -31,17 +31,18 @@ var ( // Issue represents an issue or pull request of repository. type Issue struct { - Id int64 - RepoId int64 `xorm:"INDEX"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` Index int64 // Index in one repository. Name string Repo *Repository `xorm:"-"` - PosterId int64 + PosterID int64 Poster *User `xorm:"-"` LabelIds string `xorm:"TEXT"` Labels []*Label `xorm:"-"` - MilestoneId int64 - AssigneeId int64 + MilestoneID int64 + Milestone *Milestone `xorm:"-"` + AssigneeID int64 Assignee *User `xorm:"-"` IsRead bool `xorm:"-"` IsPull bool // Indicates whether is a pull request or not. @@ -55,9 +56,20 @@ type Issue struct { Updated time.Time `xorm:"UPDATED"` } +func (i *Issue) AfterSet(colName string, _ xorm.Cell) { + var err error + switch colName { + case "milestone_id": + i.Milestone, err = GetMilestoneByID(i.MilestoneID) + if err != nil { + log.Error(3, "GetMilestoneById: %v", err) + } + } +} + func (i *Issue) GetPoster() (err error) { - i.Poster, err = GetUserById(i.PosterId) - if err == ErrUserNotExist { + i.Poster, err = GetUserById(i.PosterID) + if IsErrUserNotExist(err) { i.Poster = &User{Name: "FakeUser"} return nil } @@ -72,7 +84,7 @@ func (i *Issue) GetLabels() error { strIds := strings.Split(strings.TrimSuffix(i.LabelIds[1:], "|"), "|$") i.Labels = make([]*Label, 0, len(strIds)) for _, strId := range strIds { - id, _ := com.StrTo(strId).Int64() + id := com.StrTo(strId).MustInt64() if id > 0 { l, err := GetLabelById(id) if err != nil { @@ -88,45 +100,41 @@ func (i *Issue) GetLabels() error { } func (i *Issue) GetAssignee() (err error) { - if i.AssigneeId == 0 { + if i.AssigneeID == 0 { return nil } - i.Assignee, err = GetUserById(i.AssigneeId) - if err == ErrUserNotExist { + + i.Assignee, err = GetUserById(i.AssigneeID) + if IsErrUserNotExist(err) { return nil } return err } func (i *Issue) Attachments() []*Attachment { - a, _ := GetAttachmentsForIssue(i.Id) + a, _ := GetAttachmentsForIssue(i.ID) return a } func (i *Issue) AfterDelete() { - _, err := DeleteAttachmentsByIssue(i.Id, true) + _, err := DeleteAttachmentsByIssue(i.ID, true) if err != nil { - log.Info("Could not delete files for issue #%d: %s", i.Id, err) + log.Info("Could not delete files for issue #%d: %s", i.ID, err) } } // CreateIssue creates new issue for repository. func NewIssue(issue *Issue) (err error) { sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } if _, err = sess.Insert(issue); err != nil { - sess.Rollback() return err - } - - rawSql := "UPDATE `repository` SET num_issues = num_issues + 1 WHERE id = ?" - if _, err = sess.Exec(rawSql, issue.RepoId); err != nil { - sess.Rollback() + } else if _, err = sess.Exec("UPDATE `repository` SET num_issues = num_issues + 1 WHERE id = ?", issue.RepoID); err != nil { return err } @@ -134,9 +142,9 @@ func NewIssue(issue *Issue) (err error) { return err } - if issue.MilestoneId > 0 { + if issue.MilestoneID > 0 { // FIXES(280): Update milestone counter. - return ChangeMilestoneAssign(0, issue.MilestoneId, issue) + return ChangeMilestoneAssign(0, issue.MilestoneID, issue) } return @@ -167,7 +175,7 @@ func GetIssueByRef(ref string) (issue *Issue, err error) { // GetIssueByIndex returns issue by given index in repository. func GetIssueByIndex(rid, index int64) (*Issue, error) { - issue := &Issue{RepoId: rid, Index: index} + issue := &Issue{RepoID: rid, Index: index} has, err := x.Get(issue) if err != nil { return nil, err @@ -179,7 +187,7 @@ func GetIssueByIndex(rid, index int64) (*Issue, error) { // GetIssueById returns an issue by ID. func GetIssueById(id int64) (*Issue, error) { - issue := &Issue{Id: id} + issue := &Issue{ID: id} has, err := x.Get(issue) if err != nil { return nil, err @@ -189,31 +197,30 @@ func GetIssueById(id int64) (*Issue, error) { return issue, nil } -// GetIssues returns a list of issues by given conditions. -func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labelIds, sortType string) ([]Issue, error) { - sess := x.Limit(20, (page-1)*20) +// Issues returns a list of issues by given conditions. +func Issues(uid, assigneeID, repoID, posterID, milestoneID int64, page int, isClosed, isMention bool, labelIds, sortType string) ([]*Issue, error) { + sess := x.Limit(setting.IssuePagingNum, (page-1)*setting.IssuePagingNum) - if rid > 0 { - sess.Where("repo_id=?", rid).And("is_closed=?", isClosed) + if repoID > 0 { + sess.Where("issue.repo_id=?", repoID).And("issue.is_closed=?", isClosed) } else { - sess.Where("is_closed=?", isClosed) + sess.Where("issue.is_closed=?", isClosed) } - if uid > 0 { - sess.And("assignee_id=?", uid) - } else if pid > 0 { - sess.And("poster_id=?", pid) + if assigneeID > 0 { + sess.And("issue.assignee_id=?", assigneeID) + } else if posterID > 0 { + sess.And("issue.poster_id=?", posterID) } - if mid > 0 { - sess.And("milestone_id=?", mid) + if milestoneID > 0 { + sess.And("issue.milestone_id=?", milestoneID) } if len(labelIds) > 0 { for _, label := range strings.Split(labelIds, ",") { - // Prevent SQL inject. if com.StrTo(label).MustInt() > 0 { - sess.And("label_ids like '%$" + label + "|%'") + sess.And("label_ids like ?", "%$"+label+"|%") } } } @@ -235,9 +242,16 @@ func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labelIds, sort sess.Desc("created") } - var issues []Issue - err := sess.Find(&issues) - return issues, err + if isMention { + queryStr := "issue.id = issue_user.issue_id AND issue_user.is_mentioned=1" + if uid > 0 { + queryStr += " AND issue_user.uid = " + com.ToStr(uid) + } + sess.Join("INNER", "issue_user", queryStr) + } + + issues := make([]*Issue, 0, setting.IssuePagingNum) + return issues, sess.Find(&issues) } type IssueStatus int @@ -248,10 +262,9 @@ const ( ) // GetIssuesByLabel returns a list of issues by given label and repository. -func GetIssuesByLabel(repoId int64, label string) ([]*Issue, error) { +func GetIssuesByLabel(repoID, labelID int64) ([]*Issue, error) { issues := make([]*Issue, 0, 10) - err := x.Where("repo_id=?", repoId).And("label_ids like '%$" + label + "|%'").Find(&issues) - return issues, err + return issues, x.Where("repo_id=?", repoID).And("label_ids like '%$" + com.ToStr(labelID) + "|%'").Find(&issues) } // GetIssueCountByPoster returns number of issues of repository by poster. @@ -281,8 +294,9 @@ type IssueUser struct { IsClosed bool } +// FIXME: organization // NewIssueUserPairs adds new issue-user pairs for new issue of repository. -func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID int64) (err error) { +func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID int64) error { users, err := repo.GetCollaborators() if err != nil { return err @@ -295,6 +309,7 @@ func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID in isNeedAddPoster := true for _, u := range users { + iu.Id = 0 iu.Uid = u.Id iu.IsPoster = iu.Uid == posterID if isNeedAddPoster && iu.IsPoster { @@ -306,6 +321,7 @@ func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID in } } if isNeedAddPoster { + iu.Id = 0 iu.Uid = posterID iu.IsPoster = true iu.IsAssigned = iu.Uid == assigneeID @@ -314,13 +330,24 @@ func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID in } } + // Add owner's as well. + if repo.OwnerId != posterID { + iu.Id = 0 + iu.Uid = repo.OwnerId + iu.IsAssigned = iu.Uid == assigneeID + if _, err = x.Insert(iu); err != nil { + return err + } + } + return nil } // PairsContains returns true when pairs list contains given issue. -func PairsContains(ius []*IssueUser, issueId int64) int { +func PairsContains(ius []*IssueUser, issueId, uid int64) int { for i := range ius { - if ius[i].IssueId == issueId { + if ius[i].IssueId == issueId && + ius[i].Uid == uid { return i } } @@ -387,53 +414,57 @@ type IssueStats struct { // Filter modes. const ( - FM_ASSIGN = iota + 1 + FM_ALL = iota + FM_ASSIGN FM_CREATE FM_MENTION ) // GetIssueStats returns issue statistic information by given conditions. -func GetIssueStats(rid, uid int64, isShowClosed bool, filterMode int) *IssueStats { +func GetIssueStats(repoID, uid, labelID, milestoneID int64, isShowClosed bool, filterMode int) *IssueStats { stats := &IssueStats{} issue := new(Issue) - tmpSess := &xorm.Session{} - - sess := x.Where("repo_id=?", rid) - *tmpSess = *sess - stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(issue) - *tmpSess = *sess - stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(issue) - if isShowClosed { - stats.AllCount = stats.ClosedCount - } else { - stats.AllCount = stats.OpenCount - } - - if filterMode != FM_MENTION { - sess = x.Where("repo_id=?", rid) - switch filterMode { - case FM_ASSIGN: - sess.And("assignee_id=?", uid) - case FM_CREATE: - sess.And("poster_id=?", uid) - default: - goto nofilter + + queryStr := "issue.repo_id=? AND issue.is_closed=?" + if labelID > 0 { + queryStr += " AND issue.label_ids like '%$" + com.ToStr(labelID) + "|%'" + } + if milestoneID > 0 { + queryStr += " AND milestone_id=" + com.ToStr(milestoneID) + } + switch filterMode { + case FM_ALL: + stats.OpenCount, _ = x.Where(queryStr, repoID, false).Count(issue) + stats.ClosedCount, _ = x.Where(queryStr, repoID, true).Count(issue) + return stats + + case FM_ASSIGN: + queryStr += " AND assignee_id=?" + stats.OpenCount, _ = x.Where(queryStr, repoID, false, uid).Count(issue) + stats.ClosedCount, _ = x.Where(queryStr, repoID, true, uid).Count(issue) + return stats + + case FM_CREATE: + queryStr += " AND poster_id=?" + stats.OpenCount, _ = x.Where(queryStr, repoID, false, uid).Count(issue) + stats.ClosedCount, _ = x.Where(queryStr, repoID, true, uid).Count(issue) + return stats + + case FM_MENTION: + queryStr += " AND uid=? AND is_mentioned=?" + if labelID > 0 { + stats.OpenCount, _ = x.Where(queryStr, repoID, false, uid, true). + Join("INNER", "issue", "issue.id = issue_id").Count(new(IssueUser)) + stats.ClosedCount, _ = x.Where(queryStr, repoID, true, uid, true). + Join("INNER", "issue", "issue.id = issue_id").Count(new(IssueUser)) + return stats } - *tmpSess = *sess - stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(issue) - *tmpSess = *sess - stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(issue) - } else { - sess := x.Where("repo_id=?", rid).And("uid=?", uid).And("is_mentioned=?", true) - *tmpSess = *sess - stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(new(IssueUser)) - *tmpSess = *sess - stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(new(IssueUser)) - } -nofilter: - stats.AssignCount, _ = x.Where("repo_id=?", rid).And("is_closed=?", isShowClosed).And("assignee_id=?", uid).Count(issue) - stats.CreateCount, _ = x.Where("repo_id=?", rid).And("is_closed=?", isShowClosed).And("poster_id=?", uid).Count(issue) - stats.MentionCount, _ = x.Where("repo_id=?", rid).And("uid=?", uid).And("is_closed=?", isShowClosed).And("is_mentioned=?", true).Count(new(IssueUser)) + + queryStr = strings.Replace(queryStr, "issue.", "", 2) + stats.OpenCount, _ = x.Where(queryStr, repoID, false, uid, true).Count(new(IssueUser)) + stats.ClosedCount, _ = x.Where(queryStr, repoID, true, uid, true).Count(new(IssueUser)) + return stats + } return stats } @@ -448,7 +479,7 @@ func GetUserIssueStats(uid int64, filterMode int) *IssueStats { // UpdateIssue updates information of issue. func UpdateIssue(issue *Issue) error { - _, err := x.Id(issue.Id).AllCols().Update(issue) + _, err := x.Id(issue.ID).AllCols().Update(issue) if err != nil { return err @@ -518,7 +549,7 @@ func UpdateIssueUserPairsByMentions(uids []int64, iid int64) error { // Label represents a label of repository for issues. type Label struct { - Id int64 + ID int64 `xorm:"pk autoincr"` RepoId int64 `xorm:"INDEX"` Name string Color string `xorm:"VARCHAR(7)"` @@ -545,7 +576,7 @@ func GetLabelById(id int64) (*Label, error) { return nil, ErrLabelNotExist } - l := &Label{Id: id} + l := &Label{ID: id} has, err := x.Get(l) if err != nil { return nil, err @@ -564,14 +595,13 @@ func GetLabels(repoId int64) ([]*Label, error) { // UpdateLabel updates label information. func UpdateLabel(l *Label) error { - _, err := x.Id(l.Id).AllCols().Update(l) + _, err := x.Id(l.ID).AllCols().Update(l) return err } // DeleteLabel delete a label of given repository. -func DeleteLabel(repoId int64, strId string) error { - id, _ := com.StrTo(strId).Int64() - l, err := GetLabelById(id) +func DeleteLabel(repoID, labelID int64) error { + l, err := GetLabelById(labelID) if err != nil { if err == ErrLabelNotExist { return nil @@ -579,27 +609,25 @@ func DeleteLabel(repoId int64, strId string) error { return err } - issues, err := GetIssuesByLabel(repoId, strId) + issues, err := GetIssuesByLabel(repoID, labelID) if err != nil { return err } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } for _, issue := range issues { - issue.LabelIds = strings.Replace(issue.LabelIds, "$"+strId+"|", "", -1) - if _, err = sess.Id(issue.Id).AllCols().Update(issue); err != nil { - sess.Rollback() + issue.LabelIds = strings.Replace(issue.LabelIds, "$"+com.ToStr(labelID)+"|", "", -1) + if _, err = sess.Id(issue.ID).AllCols().Update(issue); err != nil { return err } } if _, err = sess.Delete(l); err != nil { - sess.Rollback() return err } return sess.Commit() @@ -614,9 +642,8 @@ func DeleteLabel(repoId int64, strId string) error { // Milestone represents a milestone of repository. type Milestone struct { - Id int64 - RepoId int64 `xorm:"INDEX"` - Index int64 + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` Name string Content string `xorm:"TEXT"` RenderedContent string `xorm:"-"` @@ -627,9 +654,23 @@ type Milestone struct { Completeness int // Percentage(1-100). Deadline time.Time DeadlineString string `xorm:"-"` + IsOverDue bool `xorm:"-"` ClosedDate time.Time } +func (m *Milestone) AfterSet(colName string, _ xorm.Cell) { + if colName == "deadline" { + if m.Deadline.Year() == 9999 { + return + } + + m.DeadlineString = m.Deadline.Format("2006-01-02") + if time.Now().After(m.Deadline) { + m.IsOverDue = true + } + } +} + // CalOpenIssues calculates the open issues of milestone. func (m *Milestone) CalOpenIssues() { m.NumOpenIssues = m.NumIssues - m.NumClosedIssues @@ -638,101 +679,119 @@ func (m *Milestone) CalOpenIssues() { // NewMilestone creates new milestone of repository. func NewMilestone(m *Milestone) (err error) { sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } if _, err = sess.Insert(m); err != nil { - sess.Rollback() return err } - rawSql := "UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?" - if _, err = sess.Exec(rawSql, m.RepoId); err != nil { - sess.Rollback() + if _, err = sess.Exec("UPDATE `repository` SET num_milestones=num_milestones+1 WHERE id=?", m.RepoID); err != nil { return err } return sess.Commit() } -// GetMilestoneById returns the milestone by given ID. -func GetMilestoneById(id int64) (*Milestone, error) { - m := &Milestone{Id: id} +// GetMilestoneByID returns the milestone of given ID. +func GetMilestoneByID(id int64) (*Milestone, error) { + m := &Milestone{ID: id} has, err := x.Get(m) if err != nil { return nil, err } else if !has { - return nil, ErrMilestoneNotExist + return nil, ErrMilestoneNotExist{id} } return m, nil } -// GetMilestoneByIndex returns the milestone of given repository and index. -func GetMilestoneByIndex(repoId, idx int64) (*Milestone, error) { - m := &Milestone{RepoId: repoId, Index: idx} - has, err := x.Get(m) - if err != nil { - return nil, err - } else if !has { - return nil, ErrMilestoneNotExist - } - return m, nil +// GetAllRepoMilestones returns all milestones of given repository. +func GetAllRepoMilestones(repoID int64) ([]*Milestone, error) { + miles := make([]*Milestone, 0, 10) + return miles, x.Where("repo_id=?", repoID).Find(&miles) } // GetMilestones returns a list of milestones of given repository and status. -func GetMilestones(repoId int64, isClosed bool) ([]*Milestone, error) { - miles := make([]*Milestone, 0, 10) - err := x.Where("repo_id=?", repoId).And("is_closed=?", isClosed).Find(&miles) - return miles, err +func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) { + miles := make([]*Milestone, 0, setting.IssuePagingNum) + sess := x.Where("repo_id=? AND is_closed=?", repoID, isClosed) + if page > 0 { + sess = sess.Limit(setting.IssuePagingNum, (page-1)*setting.IssuePagingNum) + } + return miles, sess.Find(&miles) +} + +func updateMilestone(e Engine, m *Milestone) error { + _, err := e.Id(m.ID).AllCols().Update(m) + return err } // UpdateMilestone updates information of given milestone. func UpdateMilestone(m *Milestone) error { - _, err := x.Id(m.Id).Update(m) - return err + return updateMilestone(x, m) +} + +func countRepoMilestones(e Engine, repoID int64) int64 { + count, _ := e.Where("repo_id=?", repoID).Count(new(Milestone)) + return count +} + +// CountRepoMilestones returns number of milestones in given repository. +func CountRepoMilestones(repoID int64) int64 { + return countRepoMilestones(x, repoID) +} + +func countRepoClosedMilestones(e Engine, repoID int64) int64 { + closed, _ := e.Where("repo_id=? AND is_closed=?", repoID, true).Count(new(Milestone)) + return closed +} + +// CountRepoClosedMilestones returns number of closed milestones in given repository. +func CountRepoClosedMilestones(repoID int64) int64 { + return countRepoClosedMilestones(x, repoID) +} + +// MilestoneStats returns number of open and closed milestones of given repository. +func MilestoneStats(repoID int64) (open int64, closed int64) { + open, _ = x.Where("repo_id=? AND is_closed=?", repoID, false).Count(new(Milestone)) + return open, CountRepoClosedMilestones(repoID) } // ChangeMilestoneStatus changes the milestone open/closed status. func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { - repo, err := GetRepositoryById(m.RepoId) + repo, err := GetRepositoryById(m.RepoID) if err != nil { return err } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } m.IsClosed = isClosed - if _, err = sess.Id(m.Id).AllCols().Update(m); err != nil { - sess.Rollback() + if err = updateMilestone(sess, m); err != nil { return err } - if isClosed { - repo.NumClosedMilestones++ - } else { - repo.NumClosedMilestones-- - } - if _, err = sess.Id(repo.Id).Update(repo); err != nil { - sess.Rollback() + repo.NumMilestones = int(countRepoMilestones(sess, repo.Id)) + repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.Id)) + if _, err = sess.Id(repo.Id).AllCols().Update(repo); err != nil { return err } return sess.Commit() } -// ChangeMilestoneIssueStats updates the open/closed issues counter and progress for the -// milestone associated witht the given issue. +// ChangeMilestoneIssueStats updates the open/closed issues counter and progress +// for the milestone associated witht the given issue. func ChangeMilestoneIssueStats(issue *Issue) error { - if issue.MilestoneId == 0 { + if issue.MilestoneID == 0 { return nil } - m, err := GetMilestoneById(issue.MilestoneId) - + m, err := GetMilestoneByID(issue.MilestoneID) if err != nil { return err } @@ -759,7 +818,7 @@ func ChangeMilestoneAssign(oldMid, mid int64, issue *Issue) (err error) { } if oldMid > 0 { - m, err := GetMilestoneById(oldMid) + m, err := GetMilestoneByID(oldMid) if err != nil { return err } @@ -774,20 +833,20 @@ func ChangeMilestoneAssign(oldMid, mid int64, issue *Issue) (err error) { m.Completeness = 0 } - if _, err = sess.Id(m.Id).Cols("num_issues,num_completeness,num_closed_issues").Update(m); err != nil { + if _, err = sess.Id(m.ID).Cols("num_issues,num_completeness,num_closed_issues").Update(m); err != nil { sess.Rollback() return err } rawSql := "UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?" - if _, err = sess.Exec(rawSql, issue.Id); err != nil { + if _, err = sess.Exec(rawSql, issue.ID); err != nil { sess.Rollback() return err } } if mid > 0 { - m, err := GetMilestoneById(mid) + m, err := GetMilestoneByID(mid) if err != nil { return err } @@ -802,13 +861,13 @@ func ChangeMilestoneAssign(oldMid, mid int64, issue *Issue) (err error) { } m.Completeness = m.NumClosedIssues * 100 / m.NumIssues - if _, err = sess.Id(m.Id).Cols("num_issues,num_completeness,num_closed_issues").Update(m); err != nil { + if _, err = sess.Id(m.ID).Cols("num_issues,num_completeness,num_closed_issues").Update(m); err != nil { sess.Rollback() return err } rawSql := "UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?" - if _, err = sess.Exec(rawSql, m.Id, issue.Id); err != nil { + if _, err = sess.Exec(rawSql, m.ID, issue.ID); err != nil { sess.Rollback() return err } @@ -817,34 +876,40 @@ func ChangeMilestoneAssign(oldMid, mid int64, issue *Issue) (err error) { return sess.Commit() } -// DeleteMilestone deletes a milestone. -func DeleteMilestone(m *Milestone) (err error) { - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { +// DeleteMilestoneByID deletes a milestone by given ID. +func DeleteMilestoneByID(mid int64) error { + m, err := GetMilestoneByID(mid) + if err != nil { + if IsErrMilestoneNotExist(err) { + return nil + } return err } - if _, err = sess.Delete(m); err != nil { - sess.Rollback() + repo, err := GetRepositoryById(m.RepoID) + if err != nil { return err } - rawSql := "UPDATE `repository` SET num_milestones = num_milestones - 1 WHERE id = ?" - if _, err = sess.Exec(rawSql, m.RepoId); err != nil { - sess.Rollback() + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { return err } - rawSql = "UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?" - if _, err = sess.Exec(rawSql, m.Id); err != nil { - sess.Rollback() + if _, err = sess.Id(m.ID).Delete(m); err != nil { return err } - rawSql = "UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?" - if _, err = sess.Exec(rawSql, m.Id); err != nil { - sess.Rollback() + repo.NumMilestones = int(countRepoMilestones(sess, repo.Id)) + repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.Id)) + if _, err = sess.Id(repo.Id).AllCols().Update(repo); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `issue` SET milestone_id=0 WHERE milestone_id=?", m.ID); err != nil { + return err + } else if _, err = sess.Exec("UPDATE `issue_user` SET milestone_id=0 WHERE milestone_id=?", m.ID); err != nil { return err } return sess.Commit() @@ -890,7 +955,7 @@ type Comment struct { // CreateComment creates comment of issue or commit. func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType CommentType, content string, attachments []int64) (*Comment, error) { sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err := sess.Begin(); err != nil { return nil, err } @@ -899,7 +964,6 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen CommitId: commitId, Line: line, Content: content} if _, err := sess.Insert(comment); err != nil { - sess.Rollback() return nil, err } @@ -908,7 +972,6 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen case COMMENT_TYPE_COMMENT: rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?" if _, err := sess.Exec(rawSql, issueId); err != nil { - sess.Rollback() return nil, err } @@ -922,20 +985,17 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen } if _, err := sess.Exec(rawSql, comment.Id, strings.Join(astrs, ",")); err != nil { - sess.Rollback() return nil, err } } case COMMENT_TYPE_REOPEN: rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues - 1 WHERE id = ?" if _, err := sess.Exec(rawSql, repoId); err != nil { - sess.Rollback() return nil, err } case COMMENT_TYPE_CLOSE: rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues + 1 WHERE id = ?" if _, err := sess.Exec(rawSql, repoId); err != nil { - sess.Rollback() return nil, err } } |