mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-11 11:25:42 +02:00
Merge e5591ae7c4c014cce8f5c6bb28a2fa77bf3f8aac into 0a3aaeafe7bef9d6935422f4b91c77c216c01b21
This commit is contained in:
commit
6dae55702d
@ -3622,7 +3622,13 @@
|
|||||||
"packages.terraform.delete.latest": "The latest version of a Terraform state cannot be deleted.",
|
"packages.terraform.delete.latest": "The latest version of a Terraform state cannot be deleted.",
|
||||||
"packages.vagrant.install": "To add a Vagrant box, run the following command:",
|
"packages.vagrant.install": "To add a Vagrant box, run the following command:",
|
||||||
"packages.settings.link": "Link this package to a repository",
|
"packages.settings.link": "Link this package to a repository",
|
||||||
"packages.settings.link.description": "If you link a package with a repository, the package will appear in the repository's package list. Only repositories under the same owner can be linked. Leaving the field empty will remove the link.",
|
"packages.settings.link.description": "If you link a package with a repository, the package will appear in the repository's package list.",
|
||||||
|
"packages.settings.link.notice1": "Only repositories under the same owner can be linked.",
|
||||||
|
"packages.settings.link.notice2": "Linking a repository does not change the package visibility.",
|
||||||
|
"packages.settings.link.notice3": "Leaving the field empty will remove the link.",
|
||||||
|
"packages.settings.visibility": "Package visibility",
|
||||||
|
"packages.settings.visibility.inherit": "Package visibility is inherited from the owner and cannot be changed independently here. To change it, update the visibility settings of the user or organization that owns this package.",
|
||||||
|
"packages.settings.visibility.button": "Change owner visibility",
|
||||||
"packages.settings.link.select": "Select Repository",
|
"packages.settings.link.select": "Select Repository",
|
||||||
"packages.settings.link.button": "Update Repository Link",
|
"packages.settings.link.button": "Update Repository Link",
|
||||||
"packages.settings.link.success": "Repository link was successfully updated.",
|
"packages.settings.link.success": "Repository link was successfully updated.",
|
||||||
|
|||||||
@ -9,7 +9,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
composer_module "code.gitea.io/gitea/modules/packages/composer"
|
composer_module "code.gitea.io/gitea/modules/packages/composer"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServiceIndexResponse contains registry endpoints
|
// ServiceIndexResponse contains registry endpoints
|
||||||
@ -91,7 +94,7 @@ type Source struct {
|
|||||||
Reference string `json:"reference"`
|
Reference string `json:"reference"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPackageMetadataResponse(registryURL string, pds []*packages_model.PackageDescriptor) *PackageMetadataResponse {
|
func createPackageMetadataResponse(ctx *context.Context, registryURL string, pds []*packages_model.PackageDescriptor) *PackageMetadataResponse {
|
||||||
versions := make([]*PackageVersionMetadata, 0, len(pds))
|
versions := make([]*PackageVersionMetadata, 0, len(pds))
|
||||||
|
|
||||||
for _, pd := range pds {
|
for _, pd := range pds {
|
||||||
@ -116,10 +119,15 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
if pd.Repository != nil {
|
if pd.Repository != nil {
|
||||||
pkg.Source = Source{
|
permission, err := access_model.GetDoerRepoPermission(ctx, pd.Repository, ctx.Doer)
|
||||||
URL: pd.Repository.HTMLURL(),
|
if err != nil {
|
||||||
Type: "git",
|
log.Error("GetDoerRepoPermission[%d]: %v", pd.Repository.ID, err)
|
||||||
Reference: pd.Version.Version,
|
} else if permission.HasAnyUnitAccessOrPublicAccess() {
|
||||||
|
pkg.Source = Source{
|
||||||
|
URL: pd.Repository.HTMLURL(),
|
||||||
|
Type: "git",
|
||||||
|
Reference: pd.Version.Version,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -146,6 +146,7 @@ func PackageMetadata(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp := createPackageMetadataResponse(
|
resp := createPackageMetadataResponse(
|
||||||
|
ctx,
|
||||||
setting.AppURL+"api/packages/"+ctx.Package.Owner.Name+"/composer",
|
setting.AppURL+"api/packages/"+ctx.Package.Owner.Name+"/composer",
|
||||||
pds,
|
pds,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -10,12 +10,32 @@
|
|||||||
{{template "user/overview/header" .}}
|
{{template "user/overview/header" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<p><a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a> / <strong>{{ctx.Locale.Tr "repo.settings"}}</strong></p>
|
<p>
|
||||||
|
<a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a>
|
||||||
|
<span class="label-list">
|
||||||
|
{{template "package/shared/visibility_badge" dict "Package" .PackageDescriptor.Package "Owner" .PackageDescriptor.Owner}}
|
||||||
|
</span>
|
||||||
|
/ <strong>{{ctx.Locale.Tr "repo.settings"}}</strong>
|
||||||
|
</p>
|
||||||
|
{{$visibilitySettingsLink := print AppSubUrl "/user/settings"}}
|
||||||
|
{{if .ContextUser.IsOrganization}}
|
||||||
|
{{$visibilitySettingsLink = print .ContextUser.OrganisationLink "/settings"}}
|
||||||
|
{{end}}
|
||||||
|
<h4 class="ui top attached header">
|
||||||
|
{{ctx.Locale.Tr "packages.settings.visibility"}}
|
||||||
|
</h4>
|
||||||
|
<div class="ui attached segment">
|
||||||
|
<p>{{ctx.Locale.Tr "packages.settings.visibility.inherit"}}</p>
|
||||||
|
<a class="ui basic button" href="{{$visibilitySettingsLink}}">{{ctx.Locale.Tr "packages.settings.visibility.button"}}</a>
|
||||||
|
</div>
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "packages.settings.link"}}
|
{{ctx.Locale.Tr "packages.settings.link"}}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<p>{{ctx.Locale.Tr "packages.settings.link.description"}}</p>
|
<p>{{ctx.Locale.Tr "packages.settings.link.description"}}</p>
|
||||||
|
<p>- {{ctx.Locale.Tr "packages.settings.link.notice1"}}</p>
|
||||||
|
<p>- {{ctx.Locale.Tr "packages.settings.link.notice2"}}</p>
|
||||||
|
<p>- {{ctx.Locale.Tr "packages.settings.link.notice3"}}</p>
|
||||||
<form class="ui form form-fetch-action ignore-dirty flex-text-block" action="{{.Link}}" method="post">
|
<form class="ui form form-fetch-action ignore-dirty flex-text-block" action="{{.Link}}" method="post">
|
||||||
<input type="hidden" name="action" value="link">
|
<input type="hidden" name="action" value="link">
|
||||||
<div data-global-init="initSearchRepoBox" class="ui search" data-uid="{{.PackageDescriptor.Owner.ID}}">
|
<div data-global-init="initSearchRepoBox" class="ui search" data-uid="{{.PackageDescriptor.Owner.ID}}">
|
||||||
|
|||||||
@ -18,7 +18,14 @@
|
|||||||
{{range .VersionsToRemove}}
|
{{range .VersionsToRemove}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{.Package.Type.Name}}</td>
|
<td>{{.Package.Type.Name}}</td>
|
||||||
<td>{{.Package.Name}}</td>
|
<td>
|
||||||
|
{{.Package.Name}}
|
||||||
|
{{if .Owner}}
|
||||||
|
<span class="label-list">
|
||||||
|
{{template "package/shared/visibility_badge" dict "Package" .Package "Owner" .Owner}}
|
||||||
|
</span>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
<td><a href="{{.VersionWebLink}}">{{.Version.Version}}</a></td>
|
<td><a href="{{.VersionWebLink}}">{{.Version.Version}}</a></td>
|
||||||
<td><a href="{{.Creator.HomeLink}}">{{.Creator.Name}}</a></td>
|
<td><a href="{{.Creator.HomeLink}}">{{.Creator.Name}}</a></td>
|
||||||
<td>{{FileSize .CalculateBlobSize}}</td>
|
<td>{{FileSize .CalculateBlobSize}}</td>
|
||||||
|
|||||||
@ -21,7 +21,10 @@
|
|||||||
<div class="item-main">
|
<div class="item-main">
|
||||||
<div class="item-title">
|
<div class="item-title">
|
||||||
<a href="{{.VersionWebLink}}">{{.Package.Name}}</a>
|
<a href="{{.VersionWebLink}}">{{.Package.Name}}</a>
|
||||||
<span class="ui label">{{svg .Package.Type.SVGName 16}} {{.Package.Type.Name}}</span>
|
<span class="label-list">
|
||||||
|
{{template "package/shared/visibility_badge" dict "Package" .Package "Owner" .Owner}}
|
||||||
|
<span class="ui label">{{svg .Package.Type.SVGName 16}} {{.Package.Type.Name}}</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-body">
|
<div class="item-body">
|
||||||
{{$timeStr := DateUtils.TimeSince .Version.CreatedUnix}}
|
{{$timeStr := DateUtils.TimeSince .Version.CreatedUnix}}
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
<p><a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a> / <strong>{{ctx.Locale.Tr "packages.versions"}}</strong></p>
|
<p>
|
||||||
|
<a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a>
|
||||||
|
<span class="label-list">
|
||||||
|
{{template "package/shared/visibility_badge" dict "Package" .PackageDescriptor.Package "Owner" .PackageDescriptor.Owner}}
|
||||||
|
</span>
|
||||||
|
/ <strong>{{ctx.Locale.Tr "packages.versions"}}</strong>
|
||||||
|
</p>
|
||||||
<form class="ui form ignore-dirty">
|
<form class="ui form ignore-dirty">
|
||||||
<div class="ui small fluid action input">
|
<div class="ui small fluid action input">
|
||||||
{{template "shared/search/input" dict "Value" .Query "Placeholder" (ctx.Locale.Tr "search.package_kind")}}
|
{{template "shared/search/input" dict "Value" .Query "Placeholder" (ctx.Locale.Tr "search.package_kind")}}
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
<div class="issue-title-header">
|
<div class="issue-title-header">
|
||||||
{{$packageVersionLink := print $.PackageDescriptor.PackageWebLink "/" (PathEscape .PackageDescriptor.Version.LowerVersion)}}
|
{{$packageVersionLink := print $.PackageDescriptor.PackageWebLink "/" (PathEscape .PackageDescriptor.Version.LowerVersion)}}
|
||||||
<h1>{{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}})</h1>
|
<div class="tw-flex tw-flex-wrap tw-items-center tw-gap-2">
|
||||||
|
<h1 class="tw-mb-0">{{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}})</h1>
|
||||||
|
<span class="label-list">
|
||||||
|
{{template "package/shared/visibility_badge" dict "Package" .PackageDescriptor.Package "Owner" .PackageDescriptor.Owner}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{{$timeStr := DateUtils.TimeSince .PackageDescriptor.Version.CreatedUnix}}
|
{{$timeStr := DateUtils.TimeSince .PackageDescriptor.Version.CreatedUnix}}
|
||||||
{{if .HasRepositoryAccess}}
|
{{if .HasRepositoryAccess}}
|
||||||
|
|||||||
7
templates/package/shared/visibility_badge.tmpl
Normal file
7
templates/package/shared/visibility_badge.tmpl
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{{if .Package.IsInternal}}
|
||||||
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.internal"}}</span>
|
||||||
|
{{else if .Owner.Visibility.IsPrivate}}
|
||||||
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.private"}}</span>
|
||||||
|
{{else if .Owner.Visibility.IsLimited}}
|
||||||
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.internal"}}</span>
|
||||||
|
{{end}}
|
||||||
@ -27,6 +27,8 @@ func TestPackageComposer(t *testing.T) {
|
|||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
otherUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||||
|
privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31})
|
||||||
|
|
||||||
vendorName := "gitea"
|
vendorName := "gitea"
|
||||||
projectName := "composer-package"
|
projectName := "composer-package"
|
||||||
@ -243,5 +245,83 @@ func TestPackageComposer(t *testing.T) {
|
|||||||
assert.Equal(t, repo1.HTMLURL(), pkgs[0].Source.URL)
|
assert.Equal(t, repo1.HTMLURL(), pkgs[0].Source.URL)
|
||||||
assert.Equal(t, "git", pkgs[0].Source.Type)
|
assert.Equal(t, "git", pkgs[0].Source.Type)
|
||||||
assert.Equal(t, packageVersion, pkgs[0].Source.Reference)
|
assert.Equal(t, packageVersion, pkgs[0].Source.Reference)
|
||||||
|
|
||||||
|
// Private repository links remain visible to callers who can access the repository.
|
||||||
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||||
|
err = packages.SetRepositoryLink(t.Context(), userPkgs[0].ID, repo2.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", fmt.Sprintf("%s/p2/%s/%s.json", url, vendorName, projectName)).
|
||||||
|
AddBasicAuth(user.Name)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
result = DecodeJSON(t, resp, &composer.PackageMetadataResponse{})
|
||||||
|
pkgs = result.Packages[packageName]
|
||||||
|
assert.Len(t, pkgs, 1)
|
||||||
|
assert.Equal(t, repo2.HTMLURL(), pkgs[0].Source.URL)
|
||||||
|
assert.Equal(t, "git", pkgs[0].Source.Type)
|
||||||
|
assert.Equal(t, packageVersion, pkgs[0].Source.Reference)
|
||||||
|
|
||||||
|
// Callers without repository access still get the package metadata, but not the private source URL.
|
||||||
|
req = NewRequest(t, "GET", fmt.Sprintf("%s/p2/%s/%s.json", url, vendorName, projectName)).
|
||||||
|
AddBasicAuth(otherUser.Name)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
result = DecodeJSON(t, resp, &composer.PackageMetadataResponse{})
|
||||||
|
pkgs = result.Packages[packageName]
|
||||||
|
assert.Len(t, pkgs, 1)
|
||||||
|
assert.Empty(t, pkgs[0].Source.URL)
|
||||||
|
assert.Empty(t, pkgs[0].Source.Type)
|
||||||
|
assert.Empty(t, pkgs[0].Source.Reference)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("WebVisibilityBadge", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
listReq := NewRequest(t, "GET", fmt.Sprintf("/%s/-/packages", user.Name)).
|
||||||
|
AddBasicAuth(user.Name)
|
||||||
|
listResp := MakeRequest(t, listReq, http.StatusOK)
|
||||||
|
listDoc := NewHTMLParser(t, bytes.NewReader(listResp.Body.Bytes()))
|
||||||
|
assert.Equal(t, 0, listDoc.Find(".item-title .ui.basic.label").Length())
|
||||||
|
|
||||||
|
viewReq := NewRequest(t, "GET", fmt.Sprintf("/%s/-/packages/composer/%s/%s", user.Name, neturl.PathEscape(packageName), neturl.PathEscape(packageVersion))).
|
||||||
|
AddBasicAuth(user.Name)
|
||||||
|
viewResp := MakeRequest(t, viewReq, http.StatusOK)
|
||||||
|
viewDoc := NewHTMLParser(t, bytes.NewReader(viewResp.Body.Bytes()))
|
||||||
|
assert.Equal(t, 0, viewDoc.Find(".issue-title-header .ui.basic.label").Length())
|
||||||
|
|
||||||
|
privatePackageName := privateUser.Name + "/private-composer-package"
|
||||||
|
privatePackageVersion := "1.0.0"
|
||||||
|
privateContent := test.WriteZipArchive(map[string]string{
|
||||||
|
"composer.json": `{
|
||||||
|
"name": "` + privatePackageName + `",
|
||||||
|
"description": "Private Package",
|
||||||
|
"type": "` + packageType + `",
|
||||||
|
"license": "` + packageLicense + `",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "` + packageAuthor + `"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
}).Bytes()
|
||||||
|
privateUploadURL := fmt.Sprintf("%sapi/packages/%s/composer?version=%s", setting.AppURL, privateUser.Name, privatePackageVersion)
|
||||||
|
|
||||||
|
uploadReq := NewRequestWithBody(t, "PUT", privateUploadURL, bytes.NewReader(privateContent)).
|
||||||
|
AddBasicAuth(privateUser.Name)
|
||||||
|
MakeRequest(t, uploadReq, http.StatusCreated)
|
||||||
|
privateSession := loginUser(t, privateUser.Name)
|
||||||
|
|
||||||
|
privateListReq := NewRequest(t, "GET", fmt.Sprintf("/%s/-/packages", privateUser.Name))
|
||||||
|
privateListResp := privateSession.MakeRequest(t, privateListReq, http.StatusOK)
|
||||||
|
privateListDoc := NewHTMLParser(t, bytes.NewReader(privateListResp.Body.Bytes()))
|
||||||
|
assert.Equal(t, 1, privateListDoc.Find(".item-title .ui.basic.label").Length())
|
||||||
|
assert.Equal(t, "Private", privateListDoc.Find(".item-title .ui.basic.label").First().Text())
|
||||||
|
|
||||||
|
privateViewReq := NewRequest(t, "GET", fmt.Sprintf("/%s/-/packages/composer/%s/%s", privateUser.Name, neturl.PathEscape(privatePackageName), neturl.PathEscape(privatePackageVersion)))
|
||||||
|
privateViewResp := privateSession.MakeRequest(t, privateViewReq, http.StatusOK)
|
||||||
|
privateViewDoc := NewHTMLParser(t, bytes.NewReader(privateViewResp.Body.Bytes()))
|
||||||
|
assert.Equal(t, 1, privateViewDoc.Find(".issue-title-header .ui.basic.label").Length())
|
||||||
|
assert.Equal(t, "Private", privateViewDoc.Find(".issue-title-header .ui.basic.label").First().Text())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user