You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package doctor
  4. import (
  5. "context"
  6. "code.gitea.io/gitea/models/db"
  7. user_model "code.gitea.io/gitea/models/user"
  8. "code.gitea.io/gitea/modules/log"
  9. "code.gitea.io/gitea/modules/storage"
  10. repo_service "code.gitea.io/gitea/services/repository"
  11. "xorm.io/builder"
  12. )
  13. func handleDeleteOrphanedRepos(ctx context.Context, logger log.Logger, autofix bool) error {
  14. test := &consistencyCheck{
  15. Name: "Repos with no existing owner",
  16. Counter: countOrphanedRepos,
  17. Fixer: deleteOrphanedRepos,
  18. FixedMessage: "Deleted all content related to orphaned repos",
  19. }
  20. return test.Run(ctx, logger, autofix)
  21. }
  22. // countOrphanedRepos count repository where user of owner_id do not exist
  23. func countOrphanedRepos(ctx context.Context) (int64, error) {
  24. return db.CountOrphanedObjects(ctx, "repository", "user", "repository.owner_id=`user`.id")
  25. }
  26. // deleteOrphanedRepos delete repository where user of owner_id do not exist
  27. func deleteOrphanedRepos(ctx context.Context) (int64, error) {
  28. if err := storage.Init(); err != nil {
  29. return 0, err
  30. }
  31. batchSize := db.MaxBatchInsertSize("repository")
  32. e := db.GetEngine(ctx)
  33. var deleted int64
  34. adminUser := &user_model.User{IsAdmin: true}
  35. for {
  36. var ids []int64
  37. if err := e.Table("`repository`").
  38. Join("LEFT", "`user`", "repository.owner_id=`user`.id").
  39. Where(builder.IsNull{"`user`.id"}).
  40. Select("`repository`.id").Limit(batchSize).Find(&ids); err != nil {
  41. return deleted, err
  42. }
  43. // if we don't get ids we have deleted them all
  44. if len(ids) == 0 {
  45. return deleted, nil
  46. }
  47. for _, id := range ids {
  48. if err := repo_service.DeleteRepositoryDirectly(ctx, adminUser, 0, id, true); err != nil {
  49. return deleted, err
  50. }
  51. deleted++
  52. }
  53. }
  54. }
  55. func init() {
  56. Register(&Check{
  57. Title: "Deleted all content related to orphaned repos",
  58. Name: "delete-orphaned-repos",
  59. IsDefault: false,
  60. Run: handleDeleteOrphanedRepos,
  61. Priority: 4,
  62. })
  63. }