mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	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>
This commit is contained in:
		| @@ -19,6 +19,7 @@ import ( | |||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  | 	"code.gitea.io/gitea/modules/util" | ||||||
|  |  | ||||||
| 	"xorm.io/builder" | 	"xorm.io/builder" | ||||||
| ) | ) | ||||||
| @@ -776,8 +777,45 @@ func DeleteTeam(t *Team) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := t.removeAllRepositories(ctx); err != nil { | 	// update branch protections | ||||||
| 		return err | 	{ | ||||||
|  | 		protections := make([]*ProtectedBranch, 0, 10) | ||||||
|  | 		err := sess.In("repo_id", | ||||||
|  | 			builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})). | ||||||
|  | 			Find(&protections) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("findProtectedBranches: %v", err) | ||||||
|  | 		} | ||||||
|  | 		for _, p := range protections { | ||||||
|  | 			var matched1, matched2, matched3 bool | ||||||
|  | 			if len(p.WhitelistTeamIDs) != 0 { | ||||||
|  | 				p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList( | ||||||
|  | 					p.WhitelistTeamIDs, t.ID) | ||||||
|  | 			} | ||||||
|  | 			if len(p.ApprovalsWhitelistTeamIDs) != 0 { | ||||||
|  | 				p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList( | ||||||
|  | 					p.ApprovalsWhitelistTeamIDs, t.ID) | ||||||
|  | 			} | ||||||
|  | 			if len(p.MergeWhitelistTeamIDs) != 0 { | ||||||
|  | 				p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList( | ||||||
|  | 					p.MergeWhitelistTeamIDs, t.ID) | ||||||
|  | 			} | ||||||
|  | 			if matched1 || matched2 || matched3 { | ||||||
|  | 				if _, err = sess.ID(p.ID).Cols( | ||||||
|  | 					"whitelist_team_i_ds", | ||||||
|  | 					"merge_whitelist_team_i_ds", | ||||||
|  | 					"approvals_whitelist_team_i_ds", | ||||||
|  | 				).Update(p); err != nil { | ||||||
|  | 					return fmt.Errorf("updateProtectedBranches: %v", err) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !t.IncludesAllRepositories { | ||||||
|  | 		if err := t.removeAllRepositories(ctx); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Delete team-user. | 	// Delete team-user. | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ import ( | |||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/structs" | 	"code.gitea.io/gitea/modules/structs" | ||||||
|  | 	"code.gitea.io/gitea/modules/util" | ||||||
|  |  | ||||||
| 	"xorm.io/builder" | 	"xorm.io/builder" | ||||||
| ) | ) | ||||||
| @@ -120,6 +121,50 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// ***** START: Branch Protections ***** | ||||||
|  | 	{ | ||||||
|  | 		const batchSize = 50 | ||||||
|  | 		for start := 0; ; start += batchSize { | ||||||
|  | 			protections := make([]*ProtectedBranch, 0, batchSize) | ||||||
|  | 			// @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings. | ||||||
|  | 			//   We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`, | ||||||
|  | 			//   though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`). | ||||||
|  | 			// Also, as we didn't update branch protections when removing entries from `access` table, | ||||||
|  | 			//   it's safer to iterate all protected branches. | ||||||
|  | 			if err = e.Limit(batchSize, start).Find(&protections); err != nil { | ||||||
|  | 				return fmt.Errorf("findProtectedBranches: %v", err) | ||||||
|  | 			} | ||||||
|  | 			if len(protections) == 0 { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			for _, p := range protections { | ||||||
|  | 				var matched1, matched2, matched3 bool | ||||||
|  | 				if len(p.WhitelistUserIDs) != 0 { | ||||||
|  | 					p.WhitelistUserIDs, matched1 = util.RemoveIDFromList( | ||||||
|  | 						p.WhitelistUserIDs, u.ID) | ||||||
|  | 				} | ||||||
|  | 				if len(p.ApprovalsWhitelistUserIDs) != 0 { | ||||||
|  | 					p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList( | ||||||
|  | 						p.ApprovalsWhitelistUserIDs, u.ID) | ||||||
|  | 				} | ||||||
|  | 				if len(p.MergeWhitelistUserIDs) != 0 { | ||||||
|  | 					p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList( | ||||||
|  | 						p.MergeWhitelistUserIDs, u.ID) | ||||||
|  | 				} | ||||||
|  | 				if matched1 || matched2 || matched3 { | ||||||
|  | 					if _, err = e.ID(p.ID).Cols( | ||||||
|  | 						"whitelist_user_i_ds", | ||||||
|  | 						"merge_whitelist_user_i_ds", | ||||||
|  | 						"approvals_whitelist_user_i_ds", | ||||||
|  | 					).Update(p); err != nil { | ||||||
|  | 						return fmt.Errorf("updateProtectedBranches: %v", err) | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// ***** END: Branch Protections ***** | ||||||
|  |  | ||||||
| 	// ***** START: PublicKey ***** | 	// ***** START: PublicKey ***** | ||||||
| 	if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil { | 	if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil { | ||||||
| 		return fmt.Errorf("deletePublicKeys: %v", err) | 		return fmt.Errorf("deletePublicKeys: %v", err) | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								modules/util/slice.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								modules/util/slice.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | // Copyright 2022 The Gitea Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a MIT-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package util | ||||||
|  |  | ||||||
|  | // RemoveIDFromList removes the given ID from the slice, if found. | ||||||
|  | // It does not preserve order, and assumes the ID is unique. | ||||||
|  | func RemoveIDFromList(list []int64, id int64) ([]int64, bool) { | ||||||
|  | 	n := len(list) - 1 | ||||||
|  | 	for i, item := range list { | ||||||
|  | 		if item == id { | ||||||
|  | 			list[i] = list[n] | ||||||
|  | 			return list[:n], true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return list, false | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user