fix: propagate is_archived from parent to child projects in ReadAll CTE
Replace the Go-side propagateArchivedState function with in-CTE propagation. The recursive SELECT uses (ap.is_archived OR p.is_archived) to inherit archived state from parent projects. The outer query uses GROUP BY with MAX(CAST(is_archived AS int)) to handle projects accessible via both direct permissions and parent traversal. When getArchived=false, a HAVING clause filters out archived projects. The is_archived filter is removed from getUserProjectsStatement so archived parents enter the CTE and propagation works correctly.
This commit is contained in:
parent
dca041459f
commit
e3045dfd00
|
|
@ -70,7 +70,7 @@ func (l *Label) hasAccessToLabel(s *xorm.Session, a web.Auth) (has bool, maxPerm
|
|||
if isLinkShare {
|
||||
where = builder.Eq{"project_id": linkShare.ProjectID}
|
||||
} else {
|
||||
where = builder.In("project_id", getUserProjectsStatement(a.GetID(), "", false).Select("l.id"))
|
||||
where = builder.In("project_id", getUserProjectsStatement(a.GetID(), "").Select("l.id"))
|
||||
createdByID = a.GetID()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ type projectOptions struct {
|
|||
getArchived bool
|
||||
}
|
||||
|
||||
func getUserProjectsStatement(userID int64, search string, getArchived bool) *builder.Builder {
|
||||
func getUserProjectsStatement(userID int64, search string) *builder.Builder {
|
||||
dialect := db.GetDialect()
|
||||
|
||||
conds := []builder.Cond{
|
||||
|
|
@ -507,16 +507,8 @@ func getUserProjectsStatement(userID int64, search string, getArchived bool) *bu
|
|||
conds = append(conds, filterCond, parentCondition)
|
||||
}
|
||||
|
||||
if !getArchived {
|
||||
conds = append(conds,
|
||||
builder.And(
|
||||
builder.Eq{"l.is_archived": false},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return builder.Dialect(dialect).
|
||||
Select("l.*").
|
||||
Select("l.id, l.title, l.description, l.identifier, l.hex_color, l.owner_id, l.parent_project_id, l.is_archived, l.background_file_id, l.background_blur_hash, l.position, l.created, l.updated").
|
||||
From("projects", "l").
|
||||
Join("LEFT", "team_projects tl", "tl.project_id = l.id").
|
||||
Join("LEFT", "team_members tm2", "tm2.team_id = tl.team_id").
|
||||
|
|
@ -541,14 +533,14 @@ func accessibleProjectIDsSubquery(a web.Auth, column string) builder.Cond {
|
|||
}
|
||||
|
||||
return builder.In(column,
|
||||
getUserProjectsStatement(u.ID, "", false).Select("l.id"),
|
||||
getUserProjectsStatement(u.ID, "").Select("l.id"),
|
||||
)
|
||||
}
|
||||
|
||||
func getAllProjectsForUser(s *xorm.Session, userID int64, opts *projectOptions) (projects []*Project, totalCount int64, err error) {
|
||||
|
||||
limit, start := getLimitFromPageIndex(opts.page, opts.perPage)
|
||||
query := getUserProjectsStatement(userID, opts.search, opts.getArchived)
|
||||
query := getUserProjectsStatement(userID, opts.search)
|
||||
|
||||
querySQLString, args, err := query.ToSQL()
|
||||
if err != nil {
|
||||
|
|
@ -562,7 +554,7 @@ func getAllProjectsForUser(s *xorm.Session, userID int64, opts *projectOptions)
|
|||
|
||||
baseQuery := querySQLString + `
|
||||
UNION ALL
|
||||
SELECT p.* FROM projects p
|
||||
SELECT p.id, p.title, p.description, p.identifier, p.hex_color, p.owner_id, p.parent_project_id, (ap.is_archived OR p.is_archived) AS is_archived, p.background_file_id, p.background_blur_hash, p.position, p.created, p.updated FROM projects p
|
||||
INNER JOIN all_projects ap ON p.parent_project_id = ap.id`
|
||||
|
||||
columnStr := strings.Join([]string{
|
||||
|
|
@ -573,17 +565,38 @@ INNER JOIN all_projects ap ON p.parent_project_id = ap.id`
|
|||
"all_projects.hex_color",
|
||||
"all_projects.owner_id",
|
||||
"CASE WHEN all_projects.parent_project_id IS NULL THEN 0 ELSE all_projects.parent_project_id END AS parent_project_id",
|
||||
"all_projects.is_archived",
|
||||
"MAX(CAST(all_projects.is_archived AS int)) AS is_archived",
|
||||
"all_projects.background_file_id",
|
||||
"all_projects.background_blur_hash",
|
||||
"all_projects.position",
|
||||
"all_projects.created",
|
||||
"all_projects.updated",
|
||||
}, ", ")
|
||||
|
||||
groupByStr := strings.Join([]string{
|
||||
"all_projects.id",
|
||||
"all_projects.title",
|
||||
"all_projects.description",
|
||||
"all_projects.identifier",
|
||||
"all_projects.hex_color",
|
||||
"all_projects.owner_id",
|
||||
"all_projects.parent_project_id",
|
||||
"all_projects.background_file_id",
|
||||
"all_projects.background_blur_hash",
|
||||
"all_projects.position",
|
||||
"all_projects.created",
|
||||
"all_projects.updated",
|
||||
}, ", ")
|
||||
|
||||
var archivedFilter string
|
||||
if !opts.getArchived {
|
||||
archivedFilter = "HAVING MAX(CAST(all_projects.is_archived AS int)) = 0 "
|
||||
}
|
||||
|
||||
currentProjects := []*Project{}
|
||||
err = s.SQL(`WITH RECURSIVE all_projects as (`+baseQuery+`)
|
||||
SELECT DISTINCT `+columnStr+` FROM all_projects
|
||||
ORDER BY all_projects.position `+limitSQL, args...).Find(¤tProjects)
|
||||
SELECT `+columnStr+` FROM all_projects
|
||||
GROUP BY `+groupByStr+` `+archivedFilter+`ORDER BY all_projects.position `+limitSQL, args...).Find(¤tProjects)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -594,7 +607,7 @@ ORDER BY all_projects.position `+limitSQL, args...).Find(¤tProjects)
|
|||
|
||||
totalCount, err = s.
|
||||
SQL(`WITH RECURSIVE all_projects as (`+baseQuery+`)
|
||||
SELECT COUNT(DISTINCT all_projects.id) FROM all_projects`, args...).
|
||||
SELECT COUNT(*) FROM (SELECT all_projects.id FROM all_projects GROUP BY all_projects.id `+archivedFilter+`) sub`, args...).
|
||||
Count(&Project{})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
|
|
|||
Loading…
Reference in New Issue