mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-23 20:17:03 +01:00
253 lines
6.4 KiB
Go
253 lines
6.4 KiB
Go
|
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||
|
// SPDX-License-Identifier: MIT
|
||
|
|
||
|
package quota
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
|
||
|
action_model "code.gitea.io/gitea/models/actions"
|
||
|
"code.gitea.io/gitea/models/db"
|
||
|
package_model "code.gitea.io/gitea/models/packages"
|
||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||
|
|
||
|
"xorm.io/builder"
|
||
|
)
|
||
|
|
||
|
type Used struct {
|
||
|
Size UsedSize
|
||
|
}
|
||
|
|
||
|
type UsedSize struct {
|
||
|
Repos UsedSizeRepos
|
||
|
Git UsedSizeGit
|
||
|
Assets UsedSizeAssets
|
||
|
}
|
||
|
|
||
|
func (u UsedSize) All() int64 {
|
||
|
return u.Repos.All() + u.Git.All(u.Repos) + u.Assets.All()
|
||
|
}
|
||
|
|
||
|
type UsedSizeRepos struct {
|
||
|
Public int64
|
||
|
Private int64
|
||
|
}
|
||
|
|
||
|
func (u UsedSizeRepos) All() int64 {
|
||
|
return u.Public + u.Private
|
||
|
}
|
||
|
|
||
|
type UsedSizeGit struct {
|
||
|
LFS int64
|
||
|
}
|
||
|
|
||
|
func (u UsedSizeGit) All(r UsedSizeRepos) int64 {
|
||
|
return u.LFS + r.All()
|
||
|
}
|
||
|
|
||
|
type UsedSizeAssets struct {
|
||
|
Attachments UsedSizeAssetsAttachments
|
||
|
Artifacts int64
|
||
|
Packages UsedSizeAssetsPackages
|
||
|
}
|
||
|
|
||
|
func (u UsedSizeAssets) All() int64 {
|
||
|
return u.Attachments.All() + u.Artifacts + u.Packages.All
|
||
|
}
|
||
|
|
||
|
type UsedSizeAssetsAttachments struct {
|
||
|
Issues int64
|
||
|
Releases int64
|
||
|
}
|
||
|
|
||
|
func (u UsedSizeAssetsAttachments) All() int64 {
|
||
|
return u.Issues + u.Releases
|
||
|
}
|
||
|
|
||
|
type UsedSizeAssetsPackages struct {
|
||
|
All int64
|
||
|
}
|
||
|
|
||
|
func (u Used) CalculateFor(subject LimitSubject) int64 {
|
||
|
switch subject {
|
||
|
case LimitSubjectNone:
|
||
|
return 0
|
||
|
case LimitSubjectSizeAll:
|
||
|
return u.Size.All()
|
||
|
case LimitSubjectSizeReposAll:
|
||
|
return u.Size.Repos.All()
|
||
|
case LimitSubjectSizeReposPublic:
|
||
|
return u.Size.Repos.Public
|
||
|
case LimitSubjectSizeReposPrivate:
|
||
|
return u.Size.Repos.Private
|
||
|
case LimitSubjectSizeGitAll:
|
||
|
return u.Size.Git.All(u.Size.Repos)
|
||
|
case LimitSubjectSizeGitLFS:
|
||
|
return u.Size.Git.LFS
|
||
|
case LimitSubjectSizeAssetsAll:
|
||
|
return u.Size.Assets.All()
|
||
|
case LimitSubjectSizeAssetsAttachmentsAll:
|
||
|
return u.Size.Assets.Attachments.All()
|
||
|
case LimitSubjectSizeAssetsAttachmentsIssues:
|
||
|
return u.Size.Assets.Attachments.Issues
|
||
|
case LimitSubjectSizeAssetsAttachmentsReleases:
|
||
|
return u.Size.Assets.Attachments.Releases
|
||
|
case LimitSubjectSizeAssetsArtifacts:
|
||
|
return u.Size.Assets.Artifacts
|
||
|
case LimitSubjectSizeAssetsPackagesAll:
|
||
|
return u.Size.Assets.Packages.All
|
||
|
case LimitSubjectSizeWiki:
|
||
|
return 0
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func makeUserOwnedCondition(q string, userID int64) builder.Cond {
|
||
|
switch q {
|
||
|
case "repositories", "attachments", "artifacts":
|
||
|
return builder.Eq{"`repository`.owner_id": userID}
|
||
|
case "packages":
|
||
|
return builder.Or(
|
||
|
builder.Eq{"`repository`.owner_id": userID},
|
||
|
builder.And(
|
||
|
builder.Eq{"`package`.repo_id": 0},
|
||
|
builder.Eq{"`package`.owner_id": userID},
|
||
|
),
|
||
|
)
|
||
|
}
|
||
|
return builder.NewCond()
|
||
|
}
|
||
|
|
||
|
func createQueryFor(ctx context.Context, userID int64, q string) db.Engine {
|
||
|
session := db.GetEngine(ctx)
|
||
|
|
||
|
switch q {
|
||
|
case "repositories":
|
||
|
session = session.Table("repository")
|
||
|
case "attachments":
|
||
|
session = session.
|
||
|
Table("attachment").
|
||
|
Join("INNER", "`repository`", "`attachment`.repo_id = `repository`.id")
|
||
|
case "artifacts":
|
||
|
session = session.
|
||
|
Table("action_artifact").
|
||
|
Join("INNER", "`repository`", "`action_artifact`.repo_id = `repository`.id")
|
||
|
case "packages":
|
||
|
session = session.
|
||
|
Table("package_version").
|
||
|
Join("INNER", "`package_file`", "`package_file`.version_id = `package_version`.id").
|
||
|
Join("INNER", "`package_blob`", "`package_file`.blob_id = `package_blob`.id").
|
||
|
Join("INNER", "`package`", "`package_version`.package_id = `package`.id").
|
||
|
Join("LEFT OUTER", "`repository`", "`package`.repo_id = `repository`.id")
|
||
|
}
|
||
|
|
||
|
return session.Where(makeUserOwnedCondition(q, userID))
|
||
|
}
|
||
|
|
||
|
func GetQuotaAttachmentsForUser(ctx context.Context, userID int64, opts db.ListOptions) (int64, *[]*repo_model.Attachment, error) {
|
||
|
var attachments []*repo_model.Attachment
|
||
|
|
||
|
sess := createQueryFor(ctx, userID, "attachments").
|
||
|
OrderBy("`attachment`.size DESC")
|
||
|
if opts.PageSize > 0 {
|
||
|
sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||
|
}
|
||
|
count, err := sess.FindAndCount(&attachments)
|
||
|
if err != nil {
|
||
|
return 0, nil, err
|
||
|
}
|
||
|
|
||
|
return count, &attachments, nil
|
||
|
}
|
||
|
|
||
|
func GetQuotaPackagesForUser(ctx context.Context, userID int64, opts db.ListOptions) (int64, *[]*package_model.PackageVersion, error) {
|
||
|
var pkgs []*package_model.PackageVersion
|
||
|
|
||
|
sess := createQueryFor(ctx, userID, "packages").
|
||
|
OrderBy("`package_blob`.size DESC")
|
||
|
if opts.PageSize > 0 {
|
||
|
sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||
|
}
|
||
|
count, err := sess.FindAndCount(&pkgs)
|
||
|
if err != nil {
|
||
|
return 0, nil, err
|
||
|
}
|
||
|
|
||
|
return count, &pkgs, nil
|
||
|
}
|
||
|
|
||
|
func GetQuotaArtifactsForUser(ctx context.Context, userID int64, opts db.ListOptions) (int64, *[]*action_model.ActionArtifact, error) {
|
||
|
var artifacts []*action_model.ActionArtifact
|
||
|
|
||
|
sess := createQueryFor(ctx, userID, "artifacts").
|
||
|
OrderBy("`action_artifact`.file_compressed_size DESC")
|
||
|
if opts.PageSize > 0 {
|
||
|
sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||
|
}
|
||
|
count, err := sess.FindAndCount(&artifacts)
|
||
|
if err != nil {
|
||
|
return 0, nil, err
|
||
|
}
|
||
|
|
||
|
return count, &artifacts, nil
|
||
|
}
|
||
|
|
||
|
func GetUsedForUser(ctx context.Context, userID int64) (*Used, error) {
|
||
|
var used Used
|
||
|
|
||
|
_, err := createQueryFor(ctx, userID, "repositories").
|
||
|
Where("`repository`.is_private = ?", true).
|
||
|
Select("SUM(git_size) AS code").
|
||
|
Get(&used.Size.Repos.Private)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
_, err = createQueryFor(ctx, userID, "repositories").
|
||
|
Where("`repository`.is_private = ?", false).
|
||
|
Select("SUM(git_size) AS code").
|
||
|
Get(&used.Size.Repos.Public)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
_, err = createQueryFor(ctx, userID, "repositories").
|
||
|
Select("SUM(lfs_size) AS lfs").
|
||
|
Get(&used.Size.Git.LFS)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
_, err = createQueryFor(ctx, userID, "attachments").
|
||
|
Select("SUM(`attachment`.size) AS size").
|
||
|
Where("`attachment`.release_id != 0").
|
||
|
Get(&used.Size.Assets.Attachments.Releases)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
_, err = createQueryFor(ctx, userID, "attachments").
|
||
|
Select("SUM(`attachment`.size) AS size").
|
||
|
Where("`attachment`.release_id = 0").
|
||
|
Get(&used.Size.Assets.Attachments.Issues)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
_, err = createQueryFor(ctx, userID, "artifacts").
|
||
|
Select("SUM(file_compressed_size) AS size").
|
||
|
Get(&used.Size.Assets.Artifacts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
_, err = createQueryFor(ctx, userID, "packages").
|
||
|
Select("SUM(package_blob.size) AS size").
|
||
|
Get(&used.Size.Assets.Packages.All)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &used, nil
|
||
|
}
|