Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions routers/api/packages/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ func CommonRoutes() *web.Router {
})
}, reqPackageAccess(perm.AccessModeRead))
r.Group("/generic", func() {
r.Get("/{packagename}/list", generic.EnumeratePackageVersions)
r.Group("/{packagename}/{packageversion}", func() {
r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
r.Group("/{filename}", func() {
Expand Down
60 changes: 60 additions & 0 deletions routers/api/packages/generic/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

packages_model "code.gitea.io/gitea/models/packages"
packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/routers/api/packages/helper"
"code.gitea.io/gitea/services/context"
packages_service "code.gitea.io/gitea/services/packages"
Expand All @@ -22,11 +23,70 @@ var (
filenameRegex = regexp.MustCompile(`\A[-_+=:;.()\[\]{}~!@#$%^& \w]+\z`)
)

// PackageFileInfo represents information about an existing package file
// swagger:model
type PackageFileInfo struct {
// Name of package file
Name string `json:"name"`
// swagger:strfmt date-time
// Date when package file was created/uploaded
CreatedUnix timeutil.TimeStamp `json:"created"`
}

// PackageInfo represents information about an existing package file
// swagger:model
type PackageInfo struct {
/// Version linked to package information
Version string `json:"version"`
/// Download count for files within version
DownloadCount int64 `json:"downloads"`
/// Files uploaded for package version
Files []PackageFileInfo `json:"files"`
}

func apiError(ctx *context.Context, status int, obj any) {
message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message)
}

// EnumeratePackageVersions lists upload versions and their associated files
func EnumeratePackageVersions(ctx *context.Context) {
pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeGeneric, ctx.PathParam("packagename"))
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
if len(pvs) == 0 {
apiError(ctx, http.StatusNotFound, err)
return
}

var info []PackageInfo
for _, pv := range pvs {
packageFiles, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}

var files []PackageFileInfo
for _, file := range packageFiles {
files = append(files, PackageFileInfo{
Name: file.Name,
CreatedUnix: file.CreatedUnix,
})
}

info = append(info, PackageInfo{
Version: pv.Version,
DownloadCount: pv.DownloadCount,
Files: files,
})
}

ctx.JSON(http.StatusOK, info)
}

// DownloadPackageFile serves the specific generic package.
func DownloadPackageFile(ctx *context.Context) {
s, u, pf, err := packages_service.OpenFileForDownloadByPackageNameAndVersion(
Expand Down