summaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
author6543 <6543@obermui.de>2022-07-30 17:52:04 +0200
committerGitHub <noreply@github.com>2022-07-30 17:52:04 +0200
commit97a8c96c5b45123f580244edbc9b2ad3e102b6ee (patch)
treec7a36363d07001c0a92040bd22db7d48f38b55e4 /models
parentd1e53bfd7f6bf62baa53c6e7b3973396db074075 (diff)
downloadgitea-97a8c96c5b45123f580244edbc9b2ad3e102b6ee.tar.gz
gitea-97a8c96c5b45123f580244edbc9b2ad3e102b6ee.zip
Add Docker /v2/_catalog endpoint (#20469) (#20556)
* Added properties for packages. * Fixed authenticate header format. * Added _catalog endpoint. * Check owner visibility. * Extracted condition. * Added test for _catalog. Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: KN4CK3R <admin@oldschoolhack.me> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Diffstat (limited to 'models')
-rw-r--r--models/migrations/migrations.go4
-rw-r--r--models/migrations/v219.go31
-rw-r--r--models/migrations/v220.go29
-rw-r--r--models/packages/container/search.go36
-rw-r--r--models/packages/descriptor.go42
-rw-r--r--models/packages/package.go17
-rw-r--r--models/packages/package_property.go10
-rw-r--r--models/user/search.go49
8 files changed, 168 insertions, 50 deletions
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 0d35ac78d3..beeba866dc 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -396,6 +396,10 @@ var migrations = []Migration{
NewMigration("Alter hook_task table TEXT fields to LONGTEXT", alterHookTaskTextFieldsToLongText),
// v218 -> v219
NewMigration("Improve Action table indices v2", improveActionTableIndices),
+ // v219 -> v220
+ NewMigration("Add sync_on_commit column to push_mirror table", addSyncOnCommitColForPushMirror),
+ // v220 -> v221
+ NewMigration("Add container repository property", addContainerRepositoryProperty),
}
// GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v219.go b/models/migrations/v219.go
new file mode 100644
index 0000000000..7b4f34b704
--- /dev/null
+++ b/models/migrations/v219.go
@@ -0,0 +1,31 @@
+// 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 migrations
+
+import (
+ "time"
+
+ "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/timeutil"
+
+ "xorm.io/xorm"
+)
+
+func addSyncOnCommitColForPushMirror(x *xorm.Engine) error {
+ type PushMirror struct {
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX"`
+ Repo *repo.Repository `xorm:"-"`
+ RemoteName string
+
+ SyncOnCommit bool `xorm:"NOT NULL DEFAULT true"`
+ Interval time.Duration
+ CreatedUnix timeutil.TimeStamp `xorm:"created"`
+ LastUpdateUnix timeutil.TimeStamp `xorm:"INDEX last_update"`
+ LastError string `xorm:"text"`
+ }
+
+ return x.Sync2(new(PushMirror))
+}
diff --git a/models/migrations/v220.go b/models/migrations/v220.go
new file mode 100644
index 0000000000..f5983582a3
--- /dev/null
+++ b/models/migrations/v220.go
@@ -0,0 +1,29 @@
+// 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 migrations
+
+import (
+ packages_model "code.gitea.io/gitea/models/packages"
+ container_module "code.gitea.io/gitea/modules/packages/container"
+
+ "xorm.io/xorm"
+ "xorm.io/xorm/schemas"
+)
+
+func addContainerRepositoryProperty(x *xorm.Engine) error {
+ switch x.Dialect().URI().DBType {
+ case schemas.SQLITE:
+ _, err := x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name || '/' || p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
+ if err != nil {
+ return err
+ }
+ default:
+ _, err := x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, CONCAT(u.lower_name, '/', p.lower_name) FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/models/packages/container/search.go b/models/packages/container/search.go
index 972cac9528..a3409fe743 100644
--- a/models/packages/container/search.go
+++ b/models/packages/container/search.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/packages"
+ user_model "code.gitea.io/gitea/models/user"
container_module "code.gitea.io/gitea/modules/packages/container"
"xorm.io/builder"
@@ -210,6 +211,7 @@ func SearchImageTags(ctx context.Context, opts *ImageTagsSearchOptions) ([]*pack
return pvs, count, err
}
+// SearchExpiredUploadedBlobs gets all uploaded blobs which are older than specified
func SearchExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) ([]*packages.PackageFile, error) {
var cond builder.Cond = builder.Eq{
"package_version.is_internal": true,
@@ -225,3 +227,37 @@ func SearchExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) ([
Where(cond).
Find(&pfs)
}
+
+// GetRepositories gets a sorted list of all repositories
+func GetRepositories(ctx context.Context, actor *user_model.User, n int, last string) ([]string, error) {
+ var cond builder.Cond = builder.Eq{
+ "package.type": packages.TypeContainer,
+ "package_property.ref_type": packages.PropertyTypePackage,
+ "package_property.name": container_module.PropertyRepository,
+ }
+
+ cond = cond.And(builder.Exists(
+ builder.
+ Select("package_version.id").
+ Where(builder.Eq{"package_version.is_internal": false}.And(builder.Expr("package.id = package_version.package_id"))).
+ From("package_version"),
+ ))
+
+ if last != "" {
+ cond = cond.And(builder.Gt{"package_property.value": strings.ToLower(last)})
+ }
+
+ cond = cond.And(user_model.BuildCanSeeUserCondition(actor))
+
+ sess := db.GetEngine(ctx).
+ Table("package").
+ Select("package_property.value").
+ Join("INNER", "user", "`user`.id = package.owner_id").
+ Join("INNER", "package_property", "package_property.ref_id = package.id").
+ Where(cond).
+ Asc("package_property.value").
+ Limit(n)
+
+ repositories := make([]string, 0, n)
+ return repositories, sess.Find(&repositories)
+}
diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go
index fbdc40f37f..31819ccca1 100644
--- a/models/packages/descriptor.go
+++ b/models/packages/descriptor.go
@@ -40,15 +40,16 @@ func (l PackagePropertyList) GetByName(name string) string {
// PackageDescriptor describes a package
type PackageDescriptor struct {
- Package *Package
- Owner *user_model.User
- Repository *repo_model.Repository
- Version *PackageVersion
- SemVer *version.Version
- Creator *user_model.User
- Properties PackagePropertyList
- Metadata interface{}
- Files []*PackageFileDescriptor
+ Package *Package
+ Owner *user_model.User
+ Repository *repo_model.Repository
+ Version *PackageVersion
+ SemVer *version.Version
+ Creator *user_model.User
+ PackageProperties PackagePropertyList
+ VersionProperties PackagePropertyList
+ Metadata interface{}
+ Files []*PackageFileDescriptor
}
// PackageFileDescriptor describes a package file
@@ -102,6 +103,10 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
return nil, err
}
}
+ pps, err := GetProperties(ctx, PropertyTypePackage, p.ID)
+ if err != nil {
+ return nil, err
+ }
pvps, err := GetProperties(ctx, PropertyTypeVersion, pv.ID)
if err != nil {
return nil, err
@@ -152,15 +157,16 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
}
return &PackageDescriptor{
- Package: p,
- Owner: o,
- Repository: repository,
- Version: pv,
- SemVer: semVer,
- Creator: creator,
- Properties: PackagePropertyList(pvps),
- Metadata: metadata,
- Files: pfds,
+ Package: p,
+ Owner: o,
+ Repository: repository,
+ Version: pv,
+ SemVer: semVer,
+ Creator: creator,
+ PackageProperties: PackagePropertyList(pps),
+ VersionProperties: PackagePropertyList(pvps),
+ Metadata: metadata,
+ Files: pfds,
}, nil
}
diff --git a/models/packages/package.go b/models/packages/package.go
index bdb535492b..97cfbc6cad 100644
--- a/models/packages/package.go
+++ b/models/packages/package.go
@@ -131,6 +131,12 @@ func TryInsertPackage(ctx context.Context, p *Package) (*Package, error) {
return p, nil
}
+// DeletePackageByID deletes a package by id
+func DeletePackageByID(ctx context.Context, packageID int64) error {
+ _, err := db.GetEngine(ctx).ID(packageID).Delete(&Package{})
+ return err
+}
+
// SetRepositoryLink sets the linked repository
func SetRepositoryLink(ctx context.Context, packageID, repoID int64) error {
_, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: repoID})
@@ -192,21 +198,20 @@ func GetPackagesByType(ctx context.Context, ownerID int64, packageType Type) ([]
Find(&ps)
}
-// DeletePackagesIfUnreferenced deletes a package if there are no associated versions
-func DeletePackagesIfUnreferenced(ctx context.Context) error {
+// FindUnreferencedPackages gets all packages without associated versions
+func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) {
in := builder.
Select("package.id").
From("package").
LeftJoin("package_version", "package_version.package_id = package.id").
Where(builder.Expr("package_version.id IS NULL"))
- _, err := db.GetEngine(ctx).
+ ps := make([]*Package, 0, 10)
+ return ps, db.GetEngine(ctx).
// double select workaround for MySQL
// https://stackoverflow.com/questions/4471277/mysql-delete-from-with-subquery-as-condition
Where(builder.In("package.id", builder.Select("id").From(in, "temp"))).
- Delete(&Package{})
-
- return err
+ Find(&ps)
}
// HasOwnerPackages tests if a user/org has packages
diff --git a/models/packages/package_property.go b/models/packages/package_property.go
index bf7dc346c6..fc10713801 100644
--- a/models/packages/package_property.go
+++ b/models/packages/package_property.go
@@ -21,9 +21,11 @@ const (
PropertyTypeVersion PropertyType = iota // 0
// PropertyTypeFile means the reference is a package file
PropertyTypeFile // 1
+ // PropertyTypePackage means the reference is a package
+ PropertyTypePackage // 2
)
-// PackageProperty represents a property of a package version or file
+// PackageProperty represents a property of a package, version or file
type PackageProperty struct {
ID int64 `xorm:"pk autoincr"`
RefType PropertyType `xorm:"INDEX NOT NULL"`
@@ -68,3 +70,9 @@ func DeletePropertyByID(ctx context.Context, propertyID int64) error {
_, err := db.GetEngine(ctx).ID(propertyID).Delete(&PackageProperty{})
return err
}
+
+// DeletePropertyByName deletes properties by name
+func DeletePropertyByName(ctx context.Context, refType PropertyType, refID int64, name string) error {
+ _, err := db.GetEngine(ctx).Where("ref_type = ? AND ref_id = ? AND name = ?", refType, refID, name).Delete(&PackageProperty{})
+ return err
+}
diff --git a/models/user/search.go b/models/user/search.go
index a81cee1c22..f8e6c89f06 100644
--- a/models/user/search.go
+++ b/models/user/search.go
@@ -58,31 +58,7 @@ func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session {
cond = cond.And(builder.In("visibility", opts.Visible))
}
- if opts.Actor != nil {
- var exprCond builder.Cond = builder.Expr("org_user.org_id = `user`.id")
-
- // If Admin - they see all users!
- if !opts.Actor.IsAdmin {
- // Force visibility for privacy
- var accessCond builder.Cond
- if !opts.Actor.IsRestricted {
- accessCond = builder.Or(
- builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))),
- builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))
- } else {
- // restricted users only see orgs they are a member of
- accessCond = builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID})))
- }
- // Don't forget about self
- accessCond = accessCond.Or(builder.Eq{"id": opts.Actor.ID})
- cond = cond.And(accessCond)
- }
-
- } else {
- // Force visibility for privacy
- // Not logged in - only public users
- cond = cond.And(builder.In("visibility", structs.VisibleTypePublic))
- }
+ cond = cond.And(BuildCanSeeUserCondition(opts.Actor))
if opts.UID > 0 {
cond = cond.And(builder.Eq{"id": opts.UID})
@@ -170,3 +146,26 @@ func IterateUser(f func(user *User) error) error {
}
}
}
+
+// BuildCanSeeUserCondition creates a condition which can be used to restrict results to users/orgs the actor can see
+func BuildCanSeeUserCondition(actor *User) builder.Cond {
+ if actor != nil {
+ // If Admin - they see all users!
+ if !actor.IsAdmin {
+ // Users can see an organization they are a member of
+ cond := builder.In("`user`.id", builder.Select("org_id").From("org_user").Where(builder.Eq{"uid": actor.ID}))
+ if !actor.IsRestricted {
+ // Not-Restricted users can see public and limited users/organizations
+ cond = cond.Or(builder.In("`user`.visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))
+ }
+ // Don't forget about self
+ return cond.Or(builder.Eq{"`user`.id": actor.ID})
+ }
+
+ return nil
+ }
+
+ // Force visibility for privacy
+ // Not logged in - only public users
+ return builder.In("`user`.visibility", structs.VisibleTypePublic)
+}