gitea源码

package_blob.go 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package packages
  4. import (
  5. "context"
  6. "strconv"
  7. "time"
  8. "code.gitea.io/gitea/models/db"
  9. "code.gitea.io/gitea/models/perm"
  10. "code.gitea.io/gitea/models/unit"
  11. user_model "code.gitea.io/gitea/models/user"
  12. "code.gitea.io/gitea/modules/structs"
  13. "code.gitea.io/gitea/modules/timeutil"
  14. "code.gitea.io/gitea/modules/util"
  15. "xorm.io/builder"
  16. )
  17. // ErrPackageBlobNotExist indicates a package blob not exist error
  18. var ErrPackageBlobNotExist = util.NewNotExistErrorf("package blob does not exist")
  19. func init() {
  20. db.RegisterModel(new(PackageBlob))
  21. }
  22. // PackageBlob represents a package blob
  23. type PackageBlob struct {
  24. ID int64 `xorm:"pk autoincr"`
  25. Size int64 `xorm:"NOT NULL DEFAULT 0"`
  26. HashMD5 string `xorm:"hash_md5 char(32) UNIQUE(md5) INDEX NOT NULL"`
  27. HashSHA1 string `xorm:"hash_sha1 char(40) UNIQUE(sha1) INDEX NOT NULL"`
  28. HashSHA256 string `xorm:"hash_sha256 char(64) UNIQUE(sha256) INDEX NOT NULL"`
  29. HashSHA512 string `xorm:"hash_sha512 char(128) UNIQUE(sha512) INDEX NOT NULL"`
  30. CreatedUnix timeutil.TimeStamp `xorm:"created INDEX NOT NULL"`
  31. }
  32. // GetOrInsertBlob inserts a blob. If the blob exists already the existing blob is returned
  33. func GetOrInsertBlob(ctx context.Context, pb *PackageBlob) (*PackageBlob, bool, error) {
  34. e := db.GetEngine(ctx)
  35. existing := &PackageBlob{}
  36. has, err := e.Where(builder.Eq{
  37. "size": pb.Size,
  38. "hash_md5": pb.HashMD5,
  39. "hash_sha1": pb.HashSHA1,
  40. "hash_sha256": pb.HashSHA256,
  41. "hash_sha512": pb.HashSHA512,
  42. }).Get(existing)
  43. if err != nil {
  44. return nil, false, err
  45. }
  46. if has {
  47. return existing, true, nil
  48. }
  49. if _, err = e.Insert(pb); err != nil {
  50. return nil, false, err
  51. }
  52. return pb, false, nil
  53. }
  54. // GetBlobByID gets a blob by id
  55. func GetBlobByID(ctx context.Context, blobID int64) (*PackageBlob, error) {
  56. pb := &PackageBlob{}
  57. has, err := db.GetEngine(ctx).ID(blobID).Get(pb)
  58. if err != nil {
  59. return nil, err
  60. }
  61. if !has {
  62. return nil, ErrPackageBlobNotExist
  63. }
  64. return pb, nil
  65. }
  66. // ExistPackageBlobWithSHA returns if a package blob exists with the provided sha
  67. func ExistPackageBlobWithSHA(ctx context.Context, blobSha256 string) (bool, error) {
  68. return db.GetEngine(ctx).Exist(&PackageBlob{
  69. HashSHA256: blobSha256,
  70. })
  71. }
  72. // FindExpiredUnreferencedBlobs gets all blobs without associated files older than the specific duration
  73. func FindExpiredUnreferencedBlobs(ctx context.Context, olderThan time.Duration) ([]*PackageBlob, error) {
  74. pbs := make([]*PackageBlob, 0, 10)
  75. return pbs, db.GetEngine(ctx).
  76. Table("package_blob").
  77. Join("LEFT", "package_file", "package_file.blob_id = package_blob.id").
  78. Where("package_file.id IS NULL AND package_blob.created_unix < ?", time.Now().Add(-olderThan).Unix()).
  79. Find(&pbs)
  80. }
  81. // DeleteBlobByID deletes a blob by id
  82. func DeleteBlobByID(ctx context.Context, blobID int64) error {
  83. _, err := db.GetEngine(ctx).ID(blobID).Delete(&PackageBlob{})
  84. return err
  85. }
  86. // GetTotalBlobSize returns the total blobs size in bytes
  87. func GetTotalBlobSize(ctx context.Context) (int64, error) {
  88. return db.GetEngine(ctx).
  89. SumInt(&PackageBlob{}, "size")
  90. }
  91. // GetTotalUnreferencedBlobSize returns the total size of all unreferenced blobs in bytes
  92. func GetTotalUnreferencedBlobSize(ctx context.Context) (int64, error) {
  93. return db.GetEngine(ctx).
  94. Table("package_blob").
  95. Join("LEFT", "package_file", "package_file.blob_id = package_blob.id").
  96. Where("package_file.id IS NULL").
  97. SumInt(&PackageBlob{}, "size")
  98. }
  99. // IsBlobAccessibleForUser tests if the user has access to the blob
  100. func IsBlobAccessibleForUser(ctx context.Context, blobID int64, user *user_model.User) (bool, error) {
  101. if user.IsAdmin {
  102. return true, nil
  103. }
  104. maxTeamAuthorize := builder.
  105. Select("max(team.authorize)").
  106. From("team").
  107. InnerJoin("team_user", "team_user.team_id = team.id").
  108. Where(builder.Eq{"team_user.uid": user.ID}.And(builder.Expr("team_user.org_id = `user`.id")))
  109. maxTeamUnitAccessMode := builder.
  110. Select("max(team_unit.access_mode)").
  111. From("team").
  112. InnerJoin("team_user", "team_user.team_id = team.id").
  113. InnerJoin("team_unit", "team_unit.team_id = team.id").
  114. Where(builder.Eq{"team_user.uid": user.ID, "team_unit.type": unit.TypePackages}.And(builder.Expr("team_user.org_id = `user`.id")))
  115. cond := builder.Eq{"package_blob.id": blobID}.And(
  116. // owner = user
  117. builder.Eq{"`user`.id": user.ID}.
  118. // user can see owner
  119. Or(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}.Or(builder.Eq{"`user`.visibility": structs.VisibleTypeLimited})).
  120. // owner is an organization and user has access to it
  121. Or(builder.Eq{"`user`.type": user_model.UserTypeOrganization}.
  122. And(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamAuthorize}.Or(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamUnitAccessMode}))),
  123. )
  124. return db.GetEngine(ctx).
  125. Table("package_blob").
  126. Join("INNER", "package_file", "package_file.blob_id = package_blob.id").
  127. Join("INNER", "package_version", "package_version.id = package_file.version_id").
  128. Join("INNER", "package", "package.id = package_version.package_id").
  129. Join("INNER", "user", "`user`.id = package.owner_id").
  130. Where(cond).
  131. Exist(&PackageBlob{})
  132. }