Skip to content

Commit 77d1c7b

Browse files
noerwlafriks
andauthored
Cleanup protected branches when deleting users & teams (#19158)
* Clean up protected_branches when deleting user fixes #19094 * Clean up protected_branches when deleting teams * fix issue Co-authored-by: Lauris BH <lauris@nix.lv>
1 parent bfe2e3d commit 77d1c7b

File tree

3 files changed

+103
-2
lines changed

3 files changed

+103
-2
lines changed

models/org_team.go

+40-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
user_model "code.gitea.io/gitea/models/user"
2020
"code.gitea.io/gitea/modules/log"
2121
"code.gitea.io/gitea/modules/setting"
22+
"code.gitea.io/gitea/modules/util"
2223

2324
"xorm.io/builder"
2425
)
@@ -776,8 +777,45 @@ func DeleteTeam(t *Team) error {
776777
return err
777778
}
778779

779-
if err := t.removeAllRepositories(ctx); err != nil {
780-
return err
780+
// update branch protections
781+
{
782+
protections := make([]*ProtectedBranch, 0, 10)
783+
err := sess.In("repo_id",
784+
builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})).
785+
Find(&protections)
786+
if err != nil {
787+
return fmt.Errorf("findProtectedBranches: %v", err)
788+
}
789+
for _, p := range protections {
790+
var matched1, matched2, matched3 bool
791+
if len(p.WhitelistTeamIDs) != 0 {
792+
p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList(
793+
p.WhitelistTeamIDs, t.ID)
794+
}
795+
if len(p.ApprovalsWhitelistTeamIDs) != 0 {
796+
p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList(
797+
p.ApprovalsWhitelistTeamIDs, t.ID)
798+
}
799+
if len(p.MergeWhitelistTeamIDs) != 0 {
800+
p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList(
801+
p.MergeWhitelistTeamIDs, t.ID)
802+
}
803+
if matched1 || matched2 || matched3 {
804+
if _, err = sess.ID(p.ID).Cols(
805+
"whitelist_team_i_ds",
806+
"merge_whitelist_team_i_ds",
807+
"approvals_whitelist_team_i_ds",
808+
).Update(p); err != nil {
809+
return fmt.Errorf("updateProtectedBranches: %v", err)
810+
}
811+
}
812+
}
813+
}
814+
815+
if !t.IncludesAllRepositories {
816+
if err := t.removeAllRepositories(ctx); err != nil {
817+
return err
818+
}
781819
}
782820

783821
// Delete team-user.

models/user.go

+45
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
user_model "code.gitea.io/gitea/models/user"
1919
"code.gitea.io/gitea/modules/setting"
2020
"code.gitea.io/gitea/modules/structs"
21+
"code.gitea.io/gitea/modules/util"
2122

2223
"xorm.io/builder"
2324
)
@@ -120,6 +121,50 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
120121
}
121122
}
122123

124+
// ***** START: Branch Protections *****
125+
{
126+
const batchSize = 50
127+
for start := 0; ; start += batchSize {
128+
protections := make([]*ProtectedBranch, 0, batchSize)
129+
// @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings.
130+
// We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`,
131+
// though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`).
132+
// Also, as we didn't update branch protections when removing entries from `access` table,
133+
// it's safer to iterate all protected branches.
134+
if err = e.Limit(batchSize, start).Find(&protections); err != nil {
135+
return fmt.Errorf("findProtectedBranches: %v", err)
136+
}
137+
if len(protections) == 0 {
138+
break
139+
}
140+
for _, p := range protections {
141+
var matched1, matched2, matched3 bool
142+
if len(p.WhitelistUserIDs) != 0 {
143+
p.WhitelistUserIDs, matched1 = util.RemoveIDFromList(
144+
p.WhitelistUserIDs, u.ID)
145+
}
146+
if len(p.ApprovalsWhitelistUserIDs) != 0 {
147+
p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList(
148+
p.ApprovalsWhitelistUserIDs, u.ID)
149+
}
150+
if len(p.MergeWhitelistUserIDs) != 0 {
151+
p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList(
152+
p.MergeWhitelistUserIDs, u.ID)
153+
}
154+
if matched1 || matched2 || matched3 {
155+
if _, err = e.ID(p.ID).Cols(
156+
"whitelist_user_i_ds",
157+
"merge_whitelist_user_i_ds",
158+
"approvals_whitelist_user_i_ds",
159+
).Update(p); err != nil {
160+
return fmt.Errorf("updateProtectedBranches: %v", err)
161+
}
162+
}
163+
}
164+
}
165+
}
166+
// ***** END: Branch Protections *****
167+
123168
// ***** START: PublicKey *****
124169
if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil {
125170
return fmt.Errorf("deletePublicKeys: %v", err)

modules/util/slice.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package util
6+
7+
// RemoveIDFromList removes the given ID from the slice, if found.
8+
// It does not preserve order, and assumes the ID is unique.
9+
func RemoveIDFromList(list []int64, id int64) ([]int64, bool) {
10+
n := len(list) - 1
11+
for i, item := range list {
12+
if item == id {
13+
list[i] = list[n]
14+
return list[:n], true
15+
}
16+
}
17+
return list, false
18+
}

0 commit comments

Comments
 (0)