summaryrefslogtreecommitdiffstats
path: root/models/issues/milestone.go
diff options
context:
space:
mode:
Diffstat (limited to 'models/issues/milestone.go')
-rw-r--r--models/issues/milestone.go334
1 files changed, 26 insertions, 308 deletions
diff --git a/models/issues/milestone.go b/models/issues/milestone.go
index 1418e0869d..c15b2a41fe 100644
--- a/models/issues/milestone.go
+++ b/models/issues/milestone.go
@@ -10,7 +10,6 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
- "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -323,261 +322,6 @@ func DeleteMilestoneByRepoID(repoID, id int64) error {
return committer.Commit()
}
-// MilestoneList is a list of milestones offering additional functionality
-type MilestoneList []*Milestone
-
-func (milestones MilestoneList) getMilestoneIDs() []int64 {
- ids := make([]int64, 0, len(milestones))
- for _, ms := range milestones {
- ids = append(ids, ms.ID)
- }
- return ids
-}
-
-// GetMilestonesOption contain options to get milestones
-type GetMilestonesOption struct {
- db.ListOptions
- RepoID int64
- State api.StateType
- Name string
- SortType string
-}
-
-func (opts GetMilestonesOption) toCond() builder.Cond {
- cond := builder.NewCond()
- if opts.RepoID != 0 {
- cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
- }
-
- switch opts.State {
- case api.StateClosed:
- cond = cond.And(builder.Eq{"is_closed": true})
- case api.StateAll:
- break
- // api.StateOpen:
- default:
- cond = cond.And(builder.Eq{"is_closed": false})
- }
-
- if len(opts.Name) != 0 {
- cond = cond.And(db.BuildCaseInsensitiveLike("name", opts.Name))
- }
-
- return cond
-}
-
-// GetMilestones returns milestones filtered by GetMilestonesOption's
-func GetMilestones(opts GetMilestonesOption) (MilestoneList, int64, error) {
- sess := db.GetEngine(db.DefaultContext).Where(opts.toCond())
-
- if opts.Page != 0 {
- sess = db.SetSessionPagination(sess, &opts)
- }
-
- switch opts.SortType {
- case "furthestduedate":
- sess.Desc("deadline_unix")
- case "leastcomplete":
- sess.Asc("completeness")
- case "mostcomplete":
- sess.Desc("completeness")
- case "leastissues":
- sess.Asc("num_issues")
- case "mostissues":
- sess.Desc("num_issues")
- case "id":
- sess.Asc("id")
- default:
- sess.Asc("deadline_unix").Asc("id")
- }
-
- miles := make([]*Milestone, 0, opts.PageSize)
- total, err := sess.FindAndCount(&miles)
- return miles, total, err
-}
-
-// GetMilestoneIDsByNames returns a list of milestone ids by given names.
-// It doesn't filter them by repo, so it could return milestones belonging to different repos.
-// It's used for filtering issues via indexer, otherwise it would be useless.
-// Since it could return milestones with the same name, so the length of returned ids could be more than the length of names.
-func GetMilestoneIDsByNames(ctx context.Context, names []string) ([]int64, error) {
- var ids []int64
- return ids, db.GetEngine(ctx).Table("milestone").
- Where(db.BuildCaseInsensitiveIn("name", names)).
- Cols("id").
- Find(&ids)
-}
-
-// SearchMilestones search milestones
-func SearchMilestones(repoCond builder.Cond, page int, isClosed bool, sortType, keyword string) (MilestoneList, error) {
- miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
- sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", isClosed)
- if len(keyword) > 0 {
- sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
- }
- if repoCond.IsValid() {
- sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
- }
- if page > 0 {
- sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
- }
-
- switch sortType {
- case "furthestduedate":
- sess.Desc("deadline_unix")
- case "leastcomplete":
- sess.Asc("completeness")
- case "mostcomplete":
- sess.Desc("completeness")
- case "leastissues":
- sess.Asc("num_issues")
- case "mostissues":
- sess.Desc("num_issues")
- default:
- sess.Asc("deadline_unix")
- }
- return miles, sess.Find(&miles)
-}
-
-// GetMilestonesByRepoIDs returns a list of milestones of given repositories and status.
-func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) {
- return SearchMilestones(
- builder.In("repo_id", repoIDs),
- page,
- isClosed,
- sortType,
- "",
- )
-}
-
-// MilestonesStats represents milestone statistic information.
-type MilestonesStats struct {
- OpenCount, ClosedCount int64
-}
-
-// Total returns the total counts of milestones
-func (m MilestonesStats) Total() int64 {
- return m.OpenCount + m.ClosedCount
-}
-
-// GetMilestonesStatsByRepoCond returns milestone statistic information for dashboard by given conditions.
-func GetMilestonesStatsByRepoCond(repoCond builder.Cond) (*MilestonesStats, error) {
- var err error
- stats := &MilestonesStats{}
-
- sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", false)
- if repoCond.IsValid() {
- sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
- }
- stats.OpenCount, err = sess.Count(new(Milestone))
- if err != nil {
- return nil, err
- }
-
- sess = db.GetEngine(db.DefaultContext).Where("is_closed = ?", true)
- if repoCond.IsValid() {
- sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
- }
- stats.ClosedCount, err = sess.Count(new(Milestone))
- if err != nil {
- return nil, err
- }
-
- return stats, nil
-}
-
-// GetMilestonesStatsByRepoCondAndKw returns milestone statistic information for dashboard by given repo conditions and name keyword.
-func GetMilestonesStatsByRepoCondAndKw(repoCond builder.Cond, keyword string) (*MilestonesStats, error) {
- var err error
- stats := &MilestonesStats{}
-
- sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", false)
- if len(keyword) > 0 {
- sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
- }
- if repoCond.IsValid() {
- sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
- }
- stats.OpenCount, err = sess.Count(new(Milestone))
- if err != nil {
- return nil, err
- }
-
- sess = db.GetEngine(db.DefaultContext).Where("is_closed = ?", true)
- if len(keyword) > 0 {
- sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
- }
- if repoCond.IsValid() {
- sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
- }
- stats.ClosedCount, err = sess.Count(new(Milestone))
- if err != nil {
- return nil, err
- }
-
- return stats, nil
-}
-
-// CountMilestones returns number of milestones in given repository with other options
-func CountMilestones(ctx context.Context, opts GetMilestonesOption) (int64, error) {
- return db.GetEngine(ctx).
- Where(opts.toCond()).
- Count(new(Milestone))
-}
-
-// CountMilestonesByRepoCond map from repo conditions to number of milestones matching the options`
-func CountMilestonesByRepoCond(repoCond builder.Cond, isClosed bool) (map[int64]int64, error) {
- sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", isClosed)
- if repoCond.IsValid() {
- sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
- }
-
- countsSlice := make([]*struct {
- RepoID int64
- Count int64
- }, 0, 10)
- if err := sess.GroupBy("repo_id").
- Select("repo_id AS repo_id, COUNT(*) AS count").
- Table("milestone").
- Find(&countsSlice); err != nil {
- return nil, err
- }
-
- countMap := make(map[int64]int64, len(countsSlice))
- for _, c := range countsSlice {
- countMap[c.RepoID] = c.Count
- }
- return countMap, nil
-}
-
-// CountMilestonesByRepoCondAndKw map from repo conditions and the keyword of milestones' name to number of milestones matching the options`
-func CountMilestonesByRepoCondAndKw(repoCond builder.Cond, keyword string, isClosed bool) (map[int64]int64, error) {
- sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", isClosed)
- if len(keyword) > 0 {
- sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
- }
- if repoCond.IsValid() {
- sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
- }
-
- countsSlice := make([]*struct {
- RepoID int64
- Count int64
- }, 0, 10)
- if err := sess.GroupBy("repo_id").
- Select("repo_id AS repo_id, COUNT(*) AS count").
- Table("milestone").
- Find(&countsSlice); err != nil {
- return nil, err
- }
-
- countMap := make(map[int64]int64, len(countsSlice))
- for _, c := range countsSlice {
- countMap[c.RepoID] = c.Count
- }
- return countMap, nil
-}
-
func updateRepoMilestoneNum(ctx context.Context, repoID int64) error {
_, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_milestones=(SELECT count(*) FROM milestone WHERE repo_id=?),num_closed_milestones=(SELECT count(*) FROM milestone WHERE repo_id=? AND is_closed=?) WHERE id=?",
repoID,
@@ -588,53 +332,6 @@ func updateRepoMilestoneNum(ctx context.Context, repoID int64) error {
return err
}
-// _____ _ _ _____ _
-// |_ _| __ __ _ ___| | _____ __| |_ _(_)_ __ ___ ___ ___
-// | || '__/ _` |/ __| |/ / _ \/ _` | | | | | '_ ` _ \ / _ \/ __|
-// | || | | (_| | (__| < __/ (_| | | | | | | | | | | __/\__ \
-// |_||_| \__,_|\___|_|\_\___|\__,_| |_| |_|_| |_| |_|\___||___/
-//
-
-func (milestones MilestoneList) loadTotalTrackedTimes(ctx context.Context) error {
- type totalTimesByMilestone struct {
- MilestoneID int64
- Time int64
- }
- if len(milestones) == 0 {
- return nil
- }
- trackedTimes := make(map[int64]int64, len(milestones))
-
- // Get total tracked time by milestone_id
- rows, err := db.GetEngine(ctx).Table("issue").
- Join("INNER", "milestone", "issue.milestone_id = milestone.id").
- Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id").
- Where("tracked_time.deleted = ?", false).
- Select("milestone_id, sum(time) as time").
- In("milestone_id", milestones.getMilestoneIDs()).
- GroupBy("milestone_id").
- Rows(new(totalTimesByMilestone))
- if err != nil {
- return err
- }
-
- defer rows.Close()
-
- for rows.Next() {
- var totalTime totalTimesByMilestone
- err = rows.Scan(&totalTime)
- if err != nil {
- return err
- }
- trackedTimes[totalTime.MilestoneID] = totalTime.Time
- }
-
- for _, milestone := range milestones {
- milestone.TotalTrackedTime = trackedTimes[milestone.ID]
- }
- return nil
-}
-
func (m *Milestone) loadTotalTrackedTime(ctx context.Context) error {
type totalTimesByMilestone struct {
MilestoneID int64
@@ -658,12 +355,33 @@ func (m *Milestone) loadTotalTrackedTime(ctx context.Context) error {
return nil
}
-// LoadTotalTrackedTimes loads for every milestone in the list the TotalTrackedTime by a batch request
-func (milestones MilestoneList) LoadTotalTrackedTimes() error {
- return milestones.loadTotalTrackedTimes(db.DefaultContext)
-}
-
// LoadTotalTrackedTime loads the tracked time for the milestone
func (m *Milestone) LoadTotalTrackedTime() error {
return m.loadTotalTrackedTime(db.DefaultContext)
}
+
+// InsertMilestones creates milestones of repository.
+func InsertMilestones(ms ...*Milestone) (err error) {
+ if len(ms) == 0 {
+ return nil
+ }
+
+ ctx, committer, err := db.TxContext(db.DefaultContext)
+ if err != nil {
+ return err
+ }
+ defer committer.Close()
+ sess := db.GetEngine(ctx)
+
+ // to return the id, so we should not use batch insert
+ for _, m := range ms {
+ if _, err = sess.NoAutoTime().Insert(m); err != nil {
+ return err
+ }
+ }
+
+ if _, err = db.Exec(ctx, "UPDATE `repository` SET num_milestones = num_milestones + ? WHERE id = ?", len(ms), ms[0].RepoID); err != nil {
+ return err
+ }
+ return committer.Commit()
+}