diff --git a/integrations/api_packages_test.go b/integrations/api_packages_test.go index b3f6e88d9f..1f24807060 100644 --- a/integrations/api_packages_test.go +++ b/integrations/api_packages_test.go @@ -71,6 +71,44 @@ func TestPackageAPI(t *testing.T) { assert.Equal(t, packageVersion, p.Version) assert.NotNil(t, p.Creator) assert.Equal(t, user.Name, p.Creator.UserName) + + t.Run("RepositoryLink", func(t *testing.T) { + defer PrintCurrentTest(t)() + + p, err := packages_model.GetPackageByName(db.DefaultContext, user.ID, packages_model.TypeGeneric, packageName) + assert.NoError(t, err) + + // no repository link + req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token)) + resp := MakeRequest(t, req, http.StatusOK) + + var ap1 *api.Package + DecodeJSON(t, resp, &ap1) + assert.Nil(t, ap1.Repository) + + // link to public repository + assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, p.ID, 1)) + + req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token)) + resp = MakeRequest(t, req, http.StatusOK) + + var ap2 *api.Package + DecodeJSON(t, resp, &ap2) + assert.NotNil(t, ap2.Repository) + assert.EqualValues(t, 1, ap2.Repository.ID) + + // link to private repository + assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, p.ID, 2)) + + req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token)) + resp = MakeRequest(t, req, http.StatusOK) + + var ap3 *api.Package + DecodeJSON(t, resp, &ap3) + assert.Nil(t, ap3.Repository) + + assert.NoError(t, packages_model.UnlinkRepositoryFromAllPackages(db.DefaultContext, 2)) + }) }) t.Run("ListPackageFiles", func(t *testing.T) { diff --git a/modules/convert/package.go b/modules/convert/package.go index 681219ca1a..a4ea41d522 100644 --- a/modules/convert/package.go +++ b/modules/convert/package.go @@ -5,28 +5,38 @@ package convert import ( + "context" + + "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/models/perm" + user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" ) // ToPackage convert a packages.PackageDescriptor to api.Package -func ToPackage(pd *packages.PackageDescriptor) *api.Package { +func ToPackage(ctx context.Context, pd *packages.PackageDescriptor, doer *user_model.User) (*api.Package, error) { var repo *api.Repository if pd.Repository != nil { - repo = ToRepo(pd.Repository, perm.AccessModeNone) + permission, err := models.GetUserRepoPermission(ctx, pd.Repository, doer) + if err != nil { + return nil, err + } + + if permission.HasAccess() { + repo = ToRepo(pd.Repository, permission.AccessMode) + } } return &api.Package{ ID: pd.Version.ID, - Owner: ToUser(pd.Owner, nil), + Owner: ToUser(pd.Owner, doer), Repository: repo, - Creator: ToUser(pd.Creator, nil), + Creator: ToUser(pd.Creator, doer), Type: string(pd.Package.Type), Name: pd.Package.Name, Version: pd.Version.Version, CreatedAt: pd.Version.CreatedUnix.AsTime(), - } + }, nil } // ToPackageFile converts packages.PackageFileDescriptor to api.PackageFile diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go index d24440d585..c59e972ed6 100644 --- a/modules/notification/webhook/webhook.go +++ b/modules/notification/webhook/webhook.go @@ -872,17 +872,19 @@ func notifyPackage(sender *user_model.User, pd *packages_model.PackageDescriptor return } - org := pd.Owner - if !org.IsOrganization() { - org = nil + ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.notifyPackage Package: %s[%d]", pd.Package.Name, pd.Package.ID)) + defer finished() + + apiPackage, err := convert.ToPackage(ctx, pd, sender) + if err != nil { + log.Error("Error converting package: %v", err) + return } if err := webhook_services.PrepareWebhooks(pd.Repository, webhook.HookEventPackage, &api.PackagePayload{ - Action: action, - Repository: convert.ToRepo(pd.Repository, perm.AccessModeNone), - Package: convert.ToPackage(pd), - Organization: convert.ToUser(org, nil), - Sender: convert.ToUser(sender, nil), + Action: action, + Package: apiPackage, + Sender: convert.ToUser(sender, nil), }); err != nil { log.Error("PrepareWebhooks: %v", err) } diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index f3aa19c319..038924737a 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -73,7 +73,12 @@ func ListPackages(ctx *context.APIContext) { apiPackages := make([]*api.Package, 0, len(pds)) for _, pd := range pds { - apiPackages = append(apiPackages, convert.ToPackage(pd)) + 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) @@ -115,7 +120,13 @@ func GetPackage(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - ctx.JSON(http.StatusOK, convert.ToPackage(ctx.Package.Descriptor)) + apiPackage, err := convert.ToPackage(ctx, ctx.Package.Descriptor, ctx.Doer) + if err != nil { + ctx.Error(http.StatusInternalServerError, "Error converting package for api", err) + return + } + + ctx.JSON(http.StatusOK, apiPackage) } // DeletePackage deletes a package diff --git a/routers/web/repo/packages.go b/routers/web/repo/packages.go index b4db2d5787..03ea4fc5f4 100644 --- a/routers/web/repo/packages.go +++ b/routers/web/repo/packages.go @@ -62,6 +62,7 @@ func Packages(ctx *context.Context) { ctx.Data["HasPackages"] = hasPackages ctx.Data["PackageDescriptors"] = pds ctx.Data["Total"] = total + ctx.Data["RepositoryAccessMap"] = map[int64]bool{ctx.Repo.Repository.ID: true} // There is only the current repository pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5) pager.AddParam(ctx, "q", "Query") diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 04b4e1e8ec..1c33998db9 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -58,6 +58,23 @@ func ListPackages(ctx *context.Context) { return } + repositoryAccessMap := make(map[int64]bool) + for _, pd := range pds { + if pd.Repository == nil { + continue + } + if _, has := repositoryAccessMap[pd.Repository.ID]; has { + continue + } + + permission, err := models.GetUserRepoPermission(ctx, pd.Repository, ctx.Doer) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return + } + repositoryAccessMap[pd.Repository.ID] = permission.HasAccess() + } + hasPackages, err := packages_model.HasOwnerPackages(ctx, ctx.ContextUser.ID) if err != nil { ctx.ServerError("HasOwnerPackages", err) @@ -72,6 +89,7 @@ func ListPackages(ctx *context.Context) { ctx.Data["HasPackages"] = hasPackages ctx.Data["PackageDescriptors"] = pds ctx.Data["Total"] = total + ctx.Data["RepositoryAccessMap"] = repositoryAccessMap pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5) pager.AddParam(ctx, "q", "Query") @@ -157,6 +175,17 @@ func ViewPackageVersion(ctx *context.Context) { ctx.Data["CanWritePackages"] = ctx.Package.AccessMode >= perm.AccessModeWrite || ctx.IsUserSiteAdmin() + hasRepositoryAccess := false + if pd.Repository != nil { + permission, err := models.GetUserRepoPermission(ctx, pd.Repository, ctx.Doer) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return + } + hasRepositoryAccess = permission.HasAccess() + } + ctx.Data["HasRepositoryAccess"] = hasRepositoryAccess + ctx.HTML(http.StatusOK, tplPackagesView) } diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl index 0b0f71283b..9e6bf5ce9e 100644 --- a/templates/package/shared/list.tmpl +++ b/templates/package/shared/list.tmpl @@ -30,7 +30,11 @@