diff options
Diffstat (limited to 'routers/api/v1/packages/package.go')
-rw-r--r-- | routers/api/v1/packages/package.go | 291 |
1 files changed, 266 insertions, 25 deletions
diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index b38aa13167..41b7f2a43f 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -4,11 +4,14 @@ package packages import ( + "errors" "net/http" "code.gitea.io/gitea/models/packages" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/optional" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" @@ -53,37 +56,18 @@ func ListPackages(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - packageType := ctx.FormTrim("type") - query := ctx.FormTrim("q") - - pvs, count, err := packages.SearchVersions(ctx, &packages.PackageSearchOptions{ + apiPackages, count, err := searchPackages(ctx, &packages.PackageSearchOptions{ OwnerID: ctx.Package.Owner.ID, - Type: packages.Type(packageType), - Name: packages.SearchValue{Value: query}, + Type: packages.Type(ctx.FormTrim("type")), + Name: packages.SearchValue{Value: ctx.FormTrim("q")}, IsInternal: optional.Some(false), Paginator: &listOptions, }) if err != nil { - ctx.Error(http.StatusInternalServerError, "SearchVersions", err) + ctx.APIErrorInternal(err) return } - pds, err := packages.GetPackageDescriptors(ctx, pvs) - if err != nil { - ctx.Error(http.StatusInternalServerError, "GetPackageDescriptors", err) - return - } - - apiPackages := make([]*api.Package, 0, len(pds)) - for _, pd := range pds { - apiPackage, err := convert.ToPackage(ctx, pd, ctx.Doer) - if err != nil { - ctx.Error(http.StatusInternalServerError, "Error converting package for api", err) - return - } - apiPackages = append(apiPackages, apiPackage) - } - ctx.SetLinkHeader(int(count), listOptions.PageSize) ctx.SetTotalCountHeader(count) ctx.JSON(http.StatusOK, apiPackages) @@ -125,7 +109,7 @@ func GetPackage(ctx *context.APIContext) { apiPackage, err := convert.ToPackage(ctx, ctx.Package.Descriptor, ctx.Doer) if err != nil { - ctx.Error(http.StatusInternalServerError, "Error converting package for api", err) + ctx.APIErrorInternal(err) return } @@ -166,7 +150,7 @@ func DeletePackage(ctx *context.APIContext) { err := packages_service.RemovePackageVersion(ctx, ctx.Doer, ctx.Package.Descriptor.Version) if err != nil { - ctx.Error(http.StatusInternalServerError, "RemovePackageVersion", err) + ctx.APIErrorInternal(err) return } ctx.Status(http.StatusNoContent) @@ -213,3 +197,260 @@ func ListPackageFiles(ctx *context.APIContext) { ctx.JSON(http.StatusOK, apiPackageFiles) } + +// ListPackageVersions gets all versions of a package +func ListPackageVersions(ctx *context.APIContext) { + // swagger:operation GET /packages/{owner}/{type}/{name} package listPackageVersions + // --- + // summary: Gets all versions of a package + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the package + // type: string + // required: true + // - name: type + // in: path + // description: type of the package + // type: string + // required: true + // - name: name + // in: path + // description: name of the package + // type: string + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results + // type: integer + // responses: + // "200": + // "$ref": "#/responses/PackageList" + // "404": + // "$ref": "#/responses/notFound" + + listOptions := utils.GetListOptions(ctx) + + apiPackages, count, err := searchPackages(ctx, &packages.PackageSearchOptions{ + OwnerID: ctx.Package.Owner.ID, + Type: packages.Type(ctx.PathParam("type")), + Name: packages.SearchValue{Value: ctx.PathParam("name"), ExactMatch: true}, + IsInternal: optional.Some(false), + Paginator: &listOptions, + }) + if err != nil { + ctx.APIErrorInternal(err) + return + } + + ctx.SetLinkHeader(int(count), listOptions.PageSize) + ctx.SetTotalCountHeader(count) + ctx.JSON(http.StatusOK, apiPackages) +} + +// GetLatestPackageVersion gets the latest version of a package +func GetLatestPackageVersion(ctx *context.APIContext) { + // swagger:operation GET /packages/{owner}/{type}/{name}/-/latest package getLatestPackageVersion + // --- + // summary: Gets the latest version of a package + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the package + // type: string + // required: true + // - name: type + // in: path + // description: type of the package + // type: string + // required: true + // - name: name + // in: path + // description: name of the package + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/Package" + // "404": + // "$ref": "#/responses/notFound" + + pvs, _, err := packages.SearchLatestVersions(ctx, &packages.PackageSearchOptions{ + OwnerID: ctx.Package.Owner.ID, + Type: packages.Type(ctx.PathParam("type")), + Name: packages.SearchValue{Value: ctx.PathParam("name"), ExactMatch: true}, + IsInternal: optional.Some(false), + }) + if err != nil { + ctx.APIErrorInternal(err) + return + } + if len(pvs) == 0 { + ctx.APIError(http.StatusNotFound, err) + return + } + + pd, err := packages.GetPackageDescriptor(ctx, pvs[0]) + if err != nil { + ctx.APIErrorInternal(err) + return + } + + apiPackage, err := convert.ToPackage(ctx, pd, ctx.Doer) + if err != nil { + ctx.APIErrorInternal(err) + return + } + + ctx.JSON(http.StatusOK, apiPackage) +} + +// LinkPackage sets a repository link for a package +func LinkPackage(ctx *context.APIContext) { + // swagger:operation POST /packages/{owner}/{type}/{name}/-/link/{repo_name} package linkPackage + // --- + // summary: Link a package to a repository + // parameters: + // - name: owner + // in: path + // description: owner of the package + // type: string + // required: true + // - name: type + // in: path + // description: type of the package + // type: string + // required: true + // - name: name + // in: path + // description: name of the package + // type: string + // required: true + // - name: repo_name + // in: path + // description: name of the repository to link. + // type: string + // required: true + // responses: + // "201": + // "$ref": "#/responses/empty" + // "404": + // "$ref": "#/responses/notFound" + + pkg, err := packages.GetPackageByName(ctx, ctx.ContextUser.ID, packages.Type(ctx.PathParam("type")), ctx.PathParam("name")) + if err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.APIError(http.StatusNotFound, err) + } else { + ctx.APIErrorInternal(err) + } + return + } + + repo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, ctx.PathParam("repo_name")) + if err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.APIError(http.StatusNotFound, err) + } else { + ctx.APIErrorInternal(err) + } + return + } + + err = packages_service.LinkToRepository(ctx, pkg, repo, ctx.Doer) + if err != nil { + switch { + case errors.Is(err, util.ErrInvalidArgument): + ctx.APIError(http.StatusBadRequest, err) + case errors.Is(err, util.ErrPermissionDenied): + ctx.APIError(http.StatusForbidden, err) + default: + ctx.APIErrorInternal(err) + } + return + } + ctx.Status(http.StatusCreated) +} + +// UnlinkPackage sets a repository link for a package +func UnlinkPackage(ctx *context.APIContext) { + // swagger:operation POST /packages/{owner}/{type}/{name}/-/unlink package unlinkPackage + // --- + // summary: Unlink a package from a repository + // parameters: + // - name: owner + // in: path + // description: owner of the package + // type: string + // required: true + // - name: type + // in: path + // description: type of the package + // type: string + // required: true + // - name: name + // in: path + // description: name of the package + // type: string + // required: true + // responses: + // "201": + // "$ref": "#/responses/empty" + // "404": + // "$ref": "#/responses/notFound" + + pkg, err := packages.GetPackageByName(ctx, ctx.ContextUser.ID, packages.Type(ctx.PathParam("type")), ctx.PathParam("name")) + if err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.APIError(http.StatusNotFound, err) + } else { + ctx.APIErrorInternal(err) + } + return + } + + err = packages_service.UnlinkFromRepository(ctx, pkg, ctx.Doer) + if err != nil { + switch { + case errors.Is(err, util.ErrPermissionDenied): + ctx.APIError(http.StatusForbidden, err) + case errors.Is(err, util.ErrInvalidArgument): + ctx.APIError(http.StatusBadRequest, err) + default: + ctx.APIErrorInternal(err) + } + return + } + ctx.Status(http.StatusNoContent) +} + +func searchPackages(ctx *context.APIContext, opts *packages.PackageSearchOptions) ([]*api.Package, int64, error) { + pvs, count, err := packages.SearchVersions(ctx, opts) + if err != nil { + return nil, 0, err + } + + pds, err := packages.GetPackageDescriptors(ctx, pvs) + if err != nil { + return nil, 0, err + } + + apiPackages := make([]*api.Package, 0, len(pds)) + for _, pd := range pds { + apiPackage, err := convert.ToPackage(ctx, pd, ctx.Doer) + if err != nil { + return nil, 0, err + } + apiPackages = append(apiPackages, apiPackage) + } + + return apiPackages, count, nil +} |