Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 12 additions & 3 deletions routers/api/packages/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,18 @@ func CommonRoutes(ctx gocontext.Context) *web.Route {
}, reqPackageAccess(perm.AccessModeWrite))
r.Get("/symbols/{filename}/{guid:[0-9a-fA-F]{32}[fF]{8}}/{filename2}", nuget.DownloadSymbolFile)
r.Get("/Packages(Id='{id:[^']+}',Version='{version:[^']+}')", nuget.RegistrationLeafV2)
r.Get("/Packages()", nuget.SearchServiceV2)
r.Get("/FindPackagesById()", nuget.EnumeratePackageVersionsV2)
r.Get("/Search()", nuget.SearchServiceV2)
r.Group("/Packages()", func() {
r.Get("", nuget.SearchServiceV2)
r.Get("/$count", nuget.SearchServiceV2Count)
})
r.Group("/FindPackagesById()", func() {
r.Get("", nuget.EnumeratePackageVersionsV2)
r.Get("/$count", nuget.EnumeratePackageVersionsV2Count)
})
r.Group("/Search()", func() {
r.Get("", nuget.SearchServiceV2)
r.Get("/$count", nuget.SearchServiceV2Count)
})
}, reqPackageAccess(perm.AccessModeRead))
})
r.Group("/npm", func() {
Expand Down
53 changes: 48 additions & 5 deletions routers/api/packages/nuget/nuget.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"
"net/http"
"regexp"
"strconv"
"strings"

"code.gitea.io/gitea/models/db"
Expand Down Expand Up @@ -94,8 +95,7 @@ func FeedCapabilityResource(ctx *context.Context) {

var searchTermExtract = regexp.MustCompile(`'([^']+)'`)

// https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Protocol/LegacyFeed/V2FeedQueryBuilder.cs
func SearchServiceV2(ctx *context.Context) {
func getSearchTerm(ctx *context.Context) string {
searchTerm := strings.Trim(ctx.FormTrim("searchTerm"), "'")
if searchTerm == "" {
// $filter contains a query like:
Expand All @@ -106,7 +106,11 @@ func SearchServiceV2(ctx *context.Context) {
searchTerm = strings.TrimSpace(match[1])
}
}
return searchTerm
}

// https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Protocol/LegacyFeed/V2FeedQueryBuilder.cs
func SearchServiceV2(ctx *context.Context) {
skip, take := ctx.FormInt("skip"), ctx.FormInt("take")
if skip == 0 {
skip = ctx.FormInt("$skip")
Expand All @@ -116,9 +120,11 @@ func SearchServiceV2(ctx *context.Context) {
}

pvs, total, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeNuGet,
Name: packages_model.SearchValue{Value: searchTerm},
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeNuGet,
Name: packages_model.SearchValue{
Value: getSearchTerm(ctx),
},
IsInternal: util.OptionalBoolFalse,
Paginator: db.NewAbsoluteListOptions(
skip,
Expand All @@ -145,6 +151,24 @@ func SearchServiceV2(ctx *context.Context) {
xmlResponse(ctx, http.StatusOK, resp)
}

// http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part2-url-conventions/odata-v4.0-errata03-os-part2-url-conventions-complete.html#_Toc453752351
func SearchServiceV2Count(ctx *context.Context) {
count, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeNuGet,
Name: packages_model.SearchValue{
Value: getSearchTerm(ctx),
},
IsInternal: util.OptionalBoolFalse,
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}

ctx.PlainText(http.StatusOK, strconv.FormatInt(count, 10))
}

// https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-for-packages
func SearchServiceV3(ctx *context.Context) {
pvs, count, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
Expand Down Expand Up @@ -288,6 +312,25 @@ func EnumeratePackageVersionsV2(ctx *context.Context) {
xmlResponse(ctx, http.StatusOK, resp)
}

// http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part2-url-conventions/odata-v4.0-errata03-os-part2-url-conventions-complete.html#_Toc453752351
func EnumeratePackageVersionsV2Count(ctx *context.Context) {
count, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeNuGet,
Name: packages_model.SearchValue{
ExactMatch: true,
Value: strings.Trim(ctx.FormTrim("id"), "'"),
},
IsInternal: util.OptionalBoolFalse,
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}

ctx.PlainText(http.StatusOK, strconv.FormatInt(count, 10))
}

// https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource#enumerate-package-versions
func EnumeratePackageVersionsV3(ctx *context.Context) {
packageName := ctx.Params("id")
Expand Down
31 changes: 20 additions & 11 deletions tests/integration/api_packages_nuget_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"io"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"time"

Expand Down Expand Up @@ -109,8 +110,6 @@ func TestPackageNuGet(t *testing.T) {
url := fmt.Sprintf("/api/packages/%s/nuget", user.Name)

t.Run("ServiceIndex", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

t.Run("v2", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

Expand Down Expand Up @@ -374,8 +373,6 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
})

t.Run("SearchService", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

cases := []struct {
Query string
Skip int
Expand All @@ -391,8 +388,6 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
}

t.Run("v2", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

t.Run("Search()", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

Expand All @@ -406,14 +401,20 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)

assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i)
assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i)

req = NewRequest(t, "GET", fmt.Sprintf("%s/Search()/$count?searchTerm='%s'&skip=%d&take=%d", url, c.Query, c.Skip, c.Take))
req = AddBasicAuthHeader(req, user.Name)
resp = MakeRequest(t, req, http.StatusOK)

assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i)
}
})

t.Run("Packages()", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

for i, c := range cases {
req := NewRequest(t, "GET", fmt.Sprintf("%s/Search()?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take))
req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take))
req = AddBasicAuthHeader(req, user.Name)
resp := MakeRequest(t, req, http.StatusOK)

Expand All @@ -422,6 +423,12 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)

assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i)
assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i)

req = NewRequest(t, "GET", fmt.Sprintf("%s/Packages()/$count?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take))
req = AddBasicAuthHeader(req, user.Name)
resp = MakeRequest(t, req, http.StatusOK)

assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i)
}
})
})
Expand Down Expand Up @@ -512,8 +519,6 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
})

t.Run("RegistrationLeaf", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

t.Run("v2", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

Expand Down Expand Up @@ -549,8 +554,6 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
})

t.Run("PackageService", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

t.Run("v2", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

Expand All @@ -563,6 +566,12 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)

assert.Len(t, result.Entries, 1)
assert.Equal(t, packageVersion, result.Entries[0].Properties.Version)

req = NewRequest(t, "GET", fmt.Sprintf("%s/FindPackagesById()/$count?id='%s'", url, packageName))
req = AddBasicAuthHeader(req, user.Name)
resp = MakeRequest(t, req, http.StatusOK)

assert.Equal(t, "1", resp.Body.String())
})

t.Run("v3", func(t *testing.T) {
Expand Down