diff --git a/pkg/models/label_rights.go b/pkg/models/label_rights.go index b737dc8bc..66fe5325c 100644 --- a/pkg/models/label_rights.go +++ b/pkg/models/label_rights.go @@ -77,7 +77,7 @@ func (l *Label) hasAccessToLabel(s *xorm.Session, a web.Auth) (has bool, maxRigh builder. Select("id"). From("tasks"). - Where(builder.In("project_id", getUserProjectsStatement(u.ID, "", false).Select("l.id"))), + Where(builder.In("project_id", getUserProjectsStatement(nil, u.ID, "", false).Select("l.id"))), ) ll := &LabelTask{} diff --git a/pkg/models/label_task.go b/pkg/models/label_task.go index 04894f402..0f19d0933 100644 --- a/pkg/models/label_task.go +++ b/pkg/models/label_task.go @@ -180,7 +180,7 @@ func getLabelsByTaskIDs(s *xorm.Session, opts *LabelByTaskIDsOptions) (ls []*lab builder. Select("id"). From("tasks"). - Where(builder.In("project_id", getUserProjectsStatement(opts.GetForUser, "", false).Select("l.id"))), + Where(builder.In("project_id", getUserProjectsStatement(nil, opts.GetForUser, "", false).Select("l.id"))), ), cond) } if opts.GetUnusedLabels { diff --git a/pkg/models/prject.go b/pkg/models/prject.go index f59deff3f..266375387 100644 --- a/pkg/models/prject.go +++ b/pkg/models/prject.go @@ -366,7 +366,7 @@ type projectOptions struct { getArchived bool } -func getUserProjectsStatement(userID int64, search string, getArchived bool) *builder.Builder { +func getUserProjectsStatement(parentProjectIDs []int64, userID int64, search string, getArchived bool) *builder.Builder { dialect := config.DatabaseType.GetString() if dialect == "sqlite" { dialect = builder.SQLITE @@ -377,7 +377,6 @@ func getUserProjectsStatement(userID int64, search string, getArchived bool) *bu if !getArchived { getArchivedCond = builder.And( builder.Eq{"l.is_archived": false}, - builder.Eq{"n.is_archived": false}, ) } @@ -400,6 +399,15 @@ func getUserProjectsStatement(userID int64, search string, getArchived bool) *bu filterCond = builder.In("l.id", ids) } + var parentCondition builder.Cond + parentCondition = builder.Or( + builder.IsNull{"parent_project_id"}, + builder.Eq{"parent_project_id": 0}, + ) + if len(parentProjectIDs) > 0 { + parentCondition = builder.In("parent_project_id", parentProjectIDs) + } + return builder.Dialect(dialect). Select("l.*"). From("projects", "l"). @@ -414,11 +422,48 @@ func getUserProjectsStatement(userID int64, search string, getArchived bool) *bu ), filterCond, getArchivedCond, + parentCondition, )). OrderBy("position"). GroupBy("l.id") } +func getAllProjectsForUser(s *xorm.Session, userID int64, parentProjectIDs []int64, opts *projectOptions, projects *[]*Project, oldTotalCount int64) (resultCount int, totalCount int64, err error) { + + limit, start := getLimitFromPageIndex(opts.page, opts.perPage) + query := getUserProjectsStatement(parentProjectIDs, userID, opts.search, opts.getArchived) + if limit > 0 { + query = query.Limit(limit, start) + } + + currentProjects := []*Project{} + err = s.SQL(query).Find(¤tProjects) + if err != nil { + return 0, 0, err + } + + if len(currentProjects) == 0 { + return 0, oldTotalCount, err + } + + query = getUserProjectsStatement(parentProjectIDs, userID, opts.search, opts.getArchived) + totalCount, err = s. + SQL(query.Select("count(*)")). + Count(&Project{}) + if err != nil { + return 0, 0, err + } + + newParentIDs := []int64{} + for _, project := range currentProjects { + newParentIDs = append(newParentIDs, project.ID) + } + + *projects = append(*projects, currentProjects...) + + return getAllProjectsForUser(s, userID, newParentIDs, opts, projects, oldTotalCount+totalCount) +} + // Gets the projects with their children without any tasks func getRawProjectsForUser(s *xorm.Session, opts *projectOptions) (projects map[int64]*Project, resultCount int, totalItems int64, err error) { fullUser, err := user.GetUserByID(s, opts.user.ID) @@ -426,30 +471,21 @@ func getRawProjectsForUser(s *xorm.Session, opts *projectOptions) (projects map[ return nil, 0, 0, err } - limit, start := getLimitFromPageIndex(opts.page, opts.perPage) - - // Gets all projects where the user is either owner or it was shared to them - - allProjects := make(map[int64]*Project) - - query := getUserProjectsStatement(fullUser.ID, opts.search, opts.getArchived) - if limit > 0 { - query = query.Limit(limit, start) - } - err = s.SQL(query).Find(&allProjects) + allProjects := []*Project{} + resultCount, totalItems, err = getAllProjectsForUser(s, fullUser.ID, nil, opts, &allProjects, 0) if err != nil { - return nil, 0, 0, err + return } - query = getUserProjectsStatement(fullUser.ID, opts.search, opts.getArchived) - totalItems, err = s. - SQL(query.Select("count(*)")). - Count(&Project{}) - if len(allProjects) == 0 { return nil, 0, totalItems, nil } + projects = make(map[int64]*Project, len(allProjects)) + for _, p := range allProjects { + projects[p.ID] = p + } + return projects, len(allProjects), totalItems, err }