mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Backport of #25613 Fixes #25564 Fixes #23191 - Api v2 search endpoint should return only the latest version matching the query - Api v3 search endpoint should return `take` packages not package versions
This commit is contained in:
		@@ -20,3 +20,19 @@ func BuildCaseInsensitiveLike(key, value string) builder.Cond {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return builder.Like{"UPPER(" + key + ")", strings.ToUpper(value)}
 | 
						return builder.Like{"UPPER(" + key + ")", strings.ToUpper(value)}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BuilderDialect returns the xorm.Builder dialect of the engine
 | 
				
			||||||
 | 
					func BuilderDialect() string {
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case setting.Database.Type.IsMySQL():
 | 
				
			||||||
 | 
							return builder.MYSQL
 | 
				
			||||||
 | 
						case setting.Database.Type.IsSQLite3():
 | 
				
			||||||
 | 
							return builder.SQLITE
 | 
				
			||||||
 | 
						case setting.Database.Type.IsPostgreSQL():
 | 
				
			||||||
 | 
							return builder.POSTGRES
 | 
				
			||||||
 | 
						case setting.Database.Type.IsMSSQL():
 | 
				
			||||||
 | 
							return builder.MSSQL
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										70
									
								
								models/packages/nuget/search.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								models/packages/nuget/search.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package nuget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
 | 
						packages_model "code.gitea.io/gitea/models/packages"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"xorm.io/builder"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SearchVersions gets all versions of packages matching the search options
 | 
				
			||||||
 | 
					func SearchVersions(ctx context.Context, opts *packages_model.PackageSearchOptions) ([]*packages_model.PackageVersion, int64, error) {
 | 
				
			||||||
 | 
						cond := toConds(opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						e := db.GetEngine(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						total, err := e.
 | 
				
			||||||
 | 
							Where(cond).
 | 
				
			||||||
 | 
							Count(&packages_model.Package{})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inner := builder.
 | 
				
			||||||
 | 
							Dialect(db.BuilderDialect()). // builder needs the sql dialect to build the Limit() below
 | 
				
			||||||
 | 
							Select("*").
 | 
				
			||||||
 | 
							From("package").
 | 
				
			||||||
 | 
							Where(cond).
 | 
				
			||||||
 | 
							OrderBy("package.name ASC")
 | 
				
			||||||
 | 
						if opts.Paginator != nil {
 | 
				
			||||||
 | 
							skip, take := opts.GetSkipTake()
 | 
				
			||||||
 | 
							inner = inner.Limit(take, skip)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sess := e.
 | 
				
			||||||
 | 
							Where(opts.ToConds()).
 | 
				
			||||||
 | 
							Table("package_version").
 | 
				
			||||||
 | 
							Join("INNER", inner, "package.id = package_version.package_id")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pvs := make([]*packages_model.PackageVersion, 0, 10)
 | 
				
			||||||
 | 
						return pvs, total, sess.Find(&pvs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CountPackages counts all packages matching the search options
 | 
				
			||||||
 | 
					func CountPackages(ctx context.Context, opts *packages_model.PackageSearchOptions) (int64, error) {
 | 
				
			||||||
 | 
						return db.GetEngine(ctx).
 | 
				
			||||||
 | 
							Where(toConds(opts)).
 | 
				
			||||||
 | 
							Count(&packages_model.Package{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func toConds(opts *packages_model.PackageSearchOptions) builder.Cond {
 | 
				
			||||||
 | 
						var cond builder.Cond = builder.Eq{
 | 
				
			||||||
 | 
							"package.is_internal": opts.IsInternal.IsTrue(),
 | 
				
			||||||
 | 
							"package.owner_id":    opts.OwnerID,
 | 
				
			||||||
 | 
							"package.type":        packages_model.TypeNuGet,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if opts.Name.Value != "" {
 | 
				
			||||||
 | 
							if opts.Name.ExactMatch {
 | 
				
			||||||
 | 
								cond = cond.And(builder.Eq{"package.lower_name": strings.ToLower(opts.Name.Value)})
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								cond = cond.And(builder.Like{"package.lower_name", strings.ToLower(opts.Name.Value)})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return cond
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -189,7 +189,7 @@ type PackageSearchOptions struct {
 | 
				
			|||||||
	db.Paginator
 | 
						db.Paginator
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (opts *PackageSearchOptions) toConds() builder.Cond {
 | 
					func (opts *PackageSearchOptions) ToConds() builder.Cond {
 | 
				
			||||||
	cond := builder.NewCond()
 | 
						cond := builder.NewCond()
 | 
				
			||||||
	if !opts.IsInternal.IsNone() {
 | 
						if !opts.IsInternal.IsNone() {
 | 
				
			||||||
		cond = builder.Eq{
 | 
							cond = builder.Eq{
 | 
				
			||||||
@@ -283,7 +283,7 @@ func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) {
 | 
				
			|||||||
// SearchVersions gets all versions of packages matching the search options
 | 
					// SearchVersions gets all versions of packages matching the search options
 | 
				
			||||||
func SearchVersions(ctx context.Context, opts *PackageSearchOptions) ([]*PackageVersion, int64, error) {
 | 
					func SearchVersions(ctx context.Context, opts *PackageSearchOptions) ([]*PackageVersion, int64, error) {
 | 
				
			||||||
	sess := db.GetEngine(ctx).
 | 
						sess := db.GetEngine(ctx).
 | 
				
			||||||
		Where(opts.toConds()).
 | 
							Where(opts.ToConds()).
 | 
				
			||||||
		Table("package_version").
 | 
							Table("package_version").
 | 
				
			||||||
		Join("INNER", "package", "package.id = package_version.package_id")
 | 
							Join("INNER", "package", "package.id = package_version.package_id")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -300,7 +300,7 @@ func SearchVersions(ctx context.Context, opts *PackageSearchOptions) ([]*Package
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// SearchLatestVersions gets the latest version of every package matching the search options
 | 
					// SearchLatestVersions gets the latest version of every package matching the search options
 | 
				
			||||||
func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*PackageVersion, int64, error) {
 | 
					func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*PackageVersion, int64, error) {
 | 
				
			||||||
	cond := opts.toConds().
 | 
						cond := opts.ToConds().
 | 
				
			||||||
		And(builder.Expr("pv2.id IS NULL"))
 | 
							And(builder.Expr("pv2.id IS NULL"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	joinCond := builder.Expr("package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))")
 | 
						joinCond := builder.Expr("package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))")
 | 
				
			||||||
@@ -328,7 +328,7 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P
 | 
				
			|||||||
// ExistVersion checks if a version matching the search options exist
 | 
					// ExistVersion checks if a version matching the search options exist
 | 
				
			||||||
func ExistVersion(ctx context.Context, opts *PackageSearchOptions) (bool, error) {
 | 
					func ExistVersion(ctx context.Context, opts *PackageSearchOptions) (bool, error) {
 | 
				
			||||||
	return db.GetEngine(ctx).
 | 
						return db.GetEngine(ctx).
 | 
				
			||||||
		Where(opts.toConds()).
 | 
							Where(opts.ToConds()).
 | 
				
			||||||
		Table("package_version").
 | 
							Table("package_version").
 | 
				
			||||||
		Join("INNER", "package", "package.id = package_version.package_id").
 | 
							Join("INNER", "package", "package.id = package_version.package_id").
 | 
				
			||||||
		Exist(new(PackageVersion))
 | 
							Exist(new(PackageVersion))
 | 
				
			||||||
@@ -337,7 +337,7 @@ func ExistVersion(ctx context.Context, opts *PackageSearchOptions) (bool, error)
 | 
				
			|||||||
// CountVersions counts all versions of packages matching the search options
 | 
					// CountVersions counts all versions of packages matching the search options
 | 
				
			||||||
func CountVersions(ctx context.Context, opts *PackageSearchOptions) (int64, error) {
 | 
					func CountVersions(ctx context.Context, opts *PackageSearchOptions) (int64, error) {
 | 
				
			||||||
	return db.GetEngine(ctx).
 | 
						return db.GetEngine(ctx).
 | 
				
			||||||
		Where(opts.toConds()).
 | 
							Where(opts.ToConds()).
 | 
				
			||||||
		Table("package_version").
 | 
							Table("package_version").
 | 
				
			||||||
		Join("INNER", "package", "package.id = package_version.package_id").
 | 
							Join("INNER", "package", "package.id = package_version.package_id").
 | 
				
			||||||
		Count(new(PackageVersion))
 | 
							Count(new(PackageVersion))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,9 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	packages_model "code.gitea.io/gitea/models/packages"
 | 
						packages_model "code.gitea.io/gitea/models/packages"
 | 
				
			||||||
	nuget_module "code.gitea.io/gitea/modules/packages/nuget"
 | 
						nuget_module "code.gitea.io/gitea/modules/packages/nuget"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"golang.org/x/text/collate"
 | 
				
			||||||
 | 
						"golang.org/x/text/language"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// https://docs.microsoft.com/en-us/nuget/api/service-index#resources
 | 
					// https://docs.microsoft.com/en-us/nuget/api/service-index#resources
 | 
				
			||||||
@@ -207,9 +210,15 @@ func createSearchResultResponse(l *linkBuilder, totalHits int64, pds []*packages
 | 
				
			|||||||
		grouped[pd.Package.Name] = append(grouped[pd.Package.Name], pd)
 | 
							grouped[pd.Package.Name] = append(grouped[pd.Package.Name], pd)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keys := make([]string, 0, len(grouped))
 | 
				
			||||||
 | 
						for key := range grouped {
 | 
				
			||||||
 | 
							keys = append(keys, key)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						collate.New(language.English, collate.IgnoreCase).SortStrings(keys)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data := make([]*SearchResult, 0, len(pds))
 | 
						data := make([]*SearchResult, 0, len(pds))
 | 
				
			||||||
	for _, group := range grouped {
 | 
						for _, key := range keys {
 | 
				
			||||||
		data = append(data, createSearchResult(l, group))
 | 
							data = append(data, createSearchResult(l, grouped[key]))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &SearchResultResponse{
 | 
						return &SearchResultResponse{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	packages_model "code.gitea.io/gitea/models/packages"
 | 
						packages_model "code.gitea.io/gitea/models/packages"
 | 
				
			||||||
 | 
						nuget_model "code.gitea.io/gitea/models/packages/nuget"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	packages_module "code.gitea.io/gitea/modules/packages"
 | 
						packages_module "code.gitea.io/gitea/modules/packages"
 | 
				
			||||||
@@ -115,7 +116,7 @@ func SearchServiceV2(ctx *context.Context) {
 | 
				
			|||||||
	skip, take := ctx.FormInt("$skip"), ctx.FormInt("$top")
 | 
						skip, take := ctx.FormInt("$skip"), ctx.FormInt("$top")
 | 
				
			||||||
	paginator := db.NewAbsoluteListOptions(skip, take)
 | 
						paginator := db.NewAbsoluteListOptions(skip, take)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pvs, total, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
 | 
						pvs, total, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
 | 
				
			||||||
		OwnerID: ctx.Package.Owner.ID,
 | 
							OwnerID: ctx.Package.Owner.ID,
 | 
				
			||||||
		Type:    packages_model.TypeNuGet,
 | 
							Type:    packages_model.TypeNuGet,
 | 
				
			||||||
		Name: packages_model.SearchValue{
 | 
							Name: packages_model.SearchValue{
 | 
				
			||||||
@@ -166,9 +167,8 @@ func SearchServiceV2(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 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
 | 
					// 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) {
 | 
					func SearchServiceV2Count(ctx *context.Context) {
 | 
				
			||||||
	count, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{
 | 
						count, err := nuget_model.CountPackages(ctx, &packages_model.PackageSearchOptions{
 | 
				
			||||||
		OwnerID: ctx.Package.Owner.ID,
 | 
							OwnerID: ctx.Package.Owner.ID,
 | 
				
			||||||
		Type:    packages_model.TypeNuGet,
 | 
					 | 
				
			||||||
		Name: packages_model.SearchValue{
 | 
							Name: packages_model.SearchValue{
 | 
				
			||||||
			Value: getSearchTerm(ctx),
 | 
								Value: getSearchTerm(ctx),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -184,9 +184,8 @@ func SearchServiceV2Count(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-for-packages
 | 
					// https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-for-packages
 | 
				
			||||||
func SearchServiceV3(ctx *context.Context) {
 | 
					func SearchServiceV3(ctx *context.Context) {
 | 
				
			||||||
	pvs, count, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
 | 
						pvs, count, err := nuget_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
 | 
				
			||||||
		OwnerID:    ctx.Package.Owner.ID,
 | 
							OwnerID:    ctx.Package.Owner.ID,
 | 
				
			||||||
		Type:       packages_model.TypeNuGet,
 | 
					 | 
				
			||||||
		Name:       packages_model.SearchValue{Value: ctx.FormTrim("q")},
 | 
							Name:       packages_model.SearchValue{Value: ctx.FormTrim("q")},
 | 
				
			||||||
		IsInternal: util.OptionalBoolFalse,
 | 
							IsInternal: util.OptionalBoolFalse,
 | 
				
			||||||
		Paginator: db.NewAbsoluteListOptions(
 | 
							Paginator: db.NewAbsoluteListOptions(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -414,6 +414,10 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
 | 
				
			|||||||
			{"test", 1, 10, 1, 0},
 | 
								{"test", 1, 10, 1, 0},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							req := NewRequestWithBody(t, "PUT", url, createPackage(packageName, "1.0.99"))
 | 
				
			||||||
 | 
							req = AddBasicAuthHeader(req, user.Name)
 | 
				
			||||||
 | 
							MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		t.Run("v2", func(t *testing.T) {
 | 
							t.Run("v2", func(t *testing.T) {
 | 
				
			||||||
			t.Run("Search()", func(t *testing.T) {
 | 
								t.Run("Search()", func(t *testing.T) {
 | 
				
			||||||
				defer tests.PrintCurrentTest(t)()
 | 
									defer tests.PrintCurrentTest(t)()
 | 
				
			||||||
@@ -493,10 +497,6 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
 | 
				
			|||||||
				req = AddBasicAuthHeader(req, user.Name)
 | 
									req = AddBasicAuthHeader(req, user.Name)
 | 
				
			||||||
				MakeRequest(t, req, http.StatusCreated)
 | 
									MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				req = NewRequestWithBody(t, "PUT", url, createPackage(packageName, "1.0.99"))
 | 
					 | 
				
			||||||
				req = AddBasicAuthHeader(req, user.Name)
 | 
					 | 
				
			||||||
				MakeRequest(t, req, http.StatusCreated)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				req = NewRequest(t, "GET", fmt.Sprintf("%s/query?q=%s", url, packageName))
 | 
									req = NewRequest(t, "GET", fmt.Sprintf("%s/query?q=%s", url, packageName))
 | 
				
			||||||
				req = AddBasicAuthHeader(req, user.Name)
 | 
									req = AddBasicAuthHeader(req, user.Name)
 | 
				
			||||||
				resp := MakeRequest(t, req, http.StatusOK)
 | 
									resp := MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
@@ -504,7 +504,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
 | 
				
			|||||||
				var result nuget.SearchResultResponse
 | 
									var result nuget.SearchResultResponse
 | 
				
			||||||
				DecodeJSON(t, resp, &result)
 | 
									DecodeJSON(t, resp, &result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				assert.EqualValues(t, 3, result.TotalHits)
 | 
									assert.EqualValues(t, 2, result.TotalHits)
 | 
				
			||||||
				assert.Len(t, result.Data, 2)
 | 
									assert.Len(t, result.Data, 2)
 | 
				
			||||||
				for _, sr := range result.Data {
 | 
									for _, sr := range result.Data {
 | 
				
			||||||
					if sr.ID == packageName {
 | 
										if sr.ID == packageName {
 | 
				
			||||||
@@ -517,12 +517,12 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
 | 
				
			|||||||
				req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName+".dummy", "1.0.0"))
 | 
									req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName+".dummy", "1.0.0"))
 | 
				
			||||||
				req = AddBasicAuthHeader(req, user.Name)
 | 
									req = AddBasicAuthHeader(req, user.Name)
 | 
				
			||||||
				MakeRequest(t, req, http.StatusNoContent)
 | 
									MakeRequest(t, req, http.StatusNoContent)
 | 
				
			||||||
 | 
					 | 
				
			||||||
				req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, "1.0.99"))
 | 
					 | 
				
			||||||
				req = AddBasicAuthHeader(req, user.Name)
 | 
					 | 
				
			||||||
				MakeRequest(t, req, http.StatusNoContent)
 | 
					 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, "1.0.99"))
 | 
				
			||||||
 | 
							req = AddBasicAuthHeader(req, user.Name)
 | 
				
			||||||
 | 
							MakeRequest(t, req, http.StatusNoContent)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("RegistrationService", func(t *testing.T) {
 | 
						t.Run("RegistrationService", func(t *testing.T) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user