mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Refactor web package and context package (#25298)
1. The "web" package shouldn't depends on "modules/context" package, instead, let each "web context" register themselves to the "web" package. 2. The old Init/Free doesn't make sense, so simplify it * The ctx in "Init(ctx)" is never used, and shouldn't be used that way * The "Free" is never called and shouldn't be called because the SSPI instance is shared --------- Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
		| @@ -191,7 +191,7 @@ func runWeb(ctx *cli.Context) error { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Set up Chi routes | 	// Set up Chi routes | ||||||
| 	c := routers.NormalRoutes(graceful.GetManager().HammerContext()) | 	c := routers.NormalRoutes() | ||||||
| 	err := listen(c, true) | 	err := listen(c, true) | ||||||
| 	<-graceful.GetManager().Done() | 	<-graceful.GetManager().Done() | ||||||
| 	log.Info("PID: %d Gitea Web Finished", os.Getpid()) | 	log.Info("PID: %d Gitea Web Finished", os.Getpid()) | ||||||
|   | |||||||
| @@ -20,6 +20,8 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/httpcache" | 	"code.gitea.io/gitea/modules/httpcache" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  | 	"code.gitea.io/gitea/modules/web" | ||||||
|  | 	web_types "code.gitea.io/gitea/modules/web/types" | ||||||
|  |  | ||||||
| 	"gitea.com/go-chi/cache" | 	"gitea.com/go-chi/cache" | ||||||
| ) | ) | ||||||
| @@ -41,6 +43,12 @@ type APIContext struct { | |||||||
| 	Package *Package | 	Package *Package | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	web.RegisterResponseStatusProvider[*APIContext](func(req *http.Request) web_types.ResponseStatusProvider { | ||||||
|  | 		return req.Context().Value(apiContextKey).(*APIContext) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
| // Currently, we have the following common fields in error response: | // Currently, we have the following common fields in error response: | ||||||
| // * message: the message for end users (it shouldn't be used for error type detection) | // * message: the message for end users (it shouldn't be used for error type detection) | ||||||
| //            if we need to indicate some errors, we should introduce some new fields like ErrorCode or ErrorType | //            if we need to indicate some errors, we should introduce some new fields like ErrorCode or ErrorType | ||||||
|   | |||||||
| @@ -96,7 +96,11 @@ func (b *Base) SetTotalCountHeader(total int64) { | |||||||
|  |  | ||||||
| // Written returns true if there are something sent to web browser | // Written returns true if there are something sent to web browser | ||||||
| func (b *Base) Written() bool { | func (b *Base) Written() bool { | ||||||
| 	return b.Resp.Status() > 0 | 	return b.Resp.WrittenStatus() != 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *Base) WrittenStatus() int { | ||||||
|  | 	return b.Resp.WrittenStatus() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Status writes status code | // Status writes status code | ||||||
|   | |||||||
| @@ -21,7 +21,9 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/templates" | 	"code.gitea.io/gitea/modules/templates" | ||||||
| 	"code.gitea.io/gitea/modules/translation" | 	"code.gitea.io/gitea/modules/translation" | ||||||
|  | 	"code.gitea.io/gitea/modules/web" | ||||||
| 	"code.gitea.io/gitea/modules/web/middleware" | 	"code.gitea.io/gitea/modules/web/middleware" | ||||||
|  | 	web_types "code.gitea.io/gitea/modules/web/types" | ||||||
|  |  | ||||||
| 	"gitea.com/go-chi/cache" | 	"gitea.com/go-chi/cache" | ||||||
| 	"gitea.com/go-chi/session" | 	"gitea.com/go-chi/session" | ||||||
| @@ -58,6 +60,12 @@ type Context struct { | |||||||
| 	Package *Package | 	Package *Package | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider { | ||||||
|  | 		return req.Context().Value(WebContextKey).(*Context) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
| // TrHTMLEscapeArgs runs ".Locale.Tr()" but pre-escapes all arguments with html.EscapeString. | // TrHTMLEscapeArgs runs ".Locale.Tr()" but pre-escapes all arguments with html.EscapeString. | ||||||
| // This is useful if the locale message is intended to only produce HTML content. | // This is useful if the locale message is intended to only produce HTML content. | ||||||
| func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string { | func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string { | ||||||
|   | |||||||
| @@ -11,6 +11,8 @@ import ( | |||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/graceful" | 	"code.gitea.io/gitea/modules/graceful" | ||||||
| 	"code.gitea.io/gitea/modules/process" | 	"code.gitea.io/gitea/modules/process" | ||||||
|  | 	"code.gitea.io/gitea/modules/web" | ||||||
|  | 	web_types "code.gitea.io/gitea/modules/web/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // PrivateContext represents a context for private routes | // PrivateContext represents a context for private routes | ||||||
| @@ -21,6 +23,12 @@ type PrivateContext struct { | |||||||
| 	Repo *Repository | 	Repo *Repository | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider { | ||||||
|  | 		return req.Context().Value(privateContextKey).(*PrivateContext) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
| // Deadline is part of the interface for context.Context and we pass this to the request context | // Deadline is part of the interface for context.Context and we pass this to the request context | ||||||
| func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) { | func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) { | ||||||
| 	if ctx.Override != nil { | 	if ctx.Override != nil { | ||||||
|   | |||||||
| @@ -5,15 +5,20 @@ package context | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
|  | 	web_types "code.gitea.io/gitea/modules/web/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ResponseWriter represents a response writer for HTTP | // ResponseWriter represents a response writer for HTTP | ||||||
| type ResponseWriter interface { | type ResponseWriter interface { | ||||||
| 	http.ResponseWriter | 	http.ResponseWriter | ||||||
| 	http.Flusher | 	http.Flusher | ||||||
| 	Status() int | 	web_types.ResponseStatusProvider | ||||||
|  |  | ||||||
| 	Before(func(ResponseWriter)) | 	Before(func(ResponseWriter)) | ||||||
| 	Size() int // used by access logger template |  | ||||||
|  | 	Status() int // used by access logger template | ||||||
|  | 	Size() int   // used by access logger template | ||||||
| } | } | ||||||
|  |  | ||||||
| var _ ResponseWriter = &Response{} | var _ ResponseWriter = &Response{} | ||||||
| @@ -46,6 +51,10 @@ func (r *Response) Write(bs []byte) (int, error) { | |||||||
| 	return size, nil | 	return size, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (r *Response) Status() int { | ||||||
|  | 	return r.status | ||||||
|  | } | ||||||
|  |  | ||||||
| func (r *Response) Size() int { | func (r *Response) Size() int { | ||||||
| 	return r.written | 	return r.written | ||||||
| } | } | ||||||
| @@ -71,8 +80,8 @@ func (r *Response) Flush() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // Status returned status code written | // WrittenStatus returned status code written | ||||||
| func (r *Response) Status() int { | func (r *Response) WrittenStatus() int { | ||||||
| 	return r.status | 	return r.status | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	access_model "code.gitea.io/gitea/models/perm/access" | 	access_model "code.gitea.io/gitea/models/perm/access" | ||||||
| @@ -25,19 +26,26 @@ import ( | |||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // MockContext mock context for unit tests | func mockRequest(t *testing.T, reqPath string) *http.Request { | ||||||
| // TODO: move this function to other packages, because it depends on "models" package | 	method, path, found := strings.Cut(reqPath, " ") | ||||||
| func MockContext(t *testing.T, path string) *context.Context { | 	if !found { | ||||||
| 	resp := httptest.NewRecorder() | 		method = "GET" | ||||||
|  | 		path = reqPath | ||||||
|  | 	} | ||||||
| 	requestURL, err := url.Parse(path) | 	requestURL, err := url.Parse(path) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	req := &http.Request{ | 	req := &http.Request{Method: method, URL: requestURL, Form: url.Values{}} | ||||||
| 		URL:  requestURL, | 	req = req.WithContext(middleware.WithContextData(req.Context())) | ||||||
| 		Form: url.Values{}, | 	return req | ||||||
| 	} | } | ||||||
|  |  | ||||||
|  | // MockContext mock context for unit tests | ||||||
|  | // TODO: move this function to other packages, because it depends on "models" package | ||||||
|  | func MockContext(t *testing.T, reqPath string) (*context.Context, *httptest.ResponseRecorder) { | ||||||
|  | 	resp := httptest.NewRecorder() | ||||||
|  | 	req := mockRequest(t, reqPath) | ||||||
| 	base, baseCleanUp := context.NewBaseContext(resp, req) | 	base, baseCleanUp := context.NewBaseContext(resp, req) | ||||||
| 	base.Data = middleware.ContextData{} | 	base.Data = middleware.GetContextData(req.Context()) | ||||||
| 	base.Locale = &translation.MockLocale{} | 	base.Locale = &translation.MockLocale{} | ||||||
| 	ctx := &context.Context{ | 	ctx := &context.Context{ | ||||||
| 		Base:   base, | 		Base:   base, | ||||||
| @@ -48,29 +56,23 @@ func MockContext(t *testing.T, path string) *context.Context { | |||||||
|  |  | ||||||
| 	chiCtx := chi.NewRouteContext() | 	chiCtx := chi.NewRouteContext() | ||||||
| 	ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) | 	ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) | ||||||
| 	return ctx | 	return ctx, resp | ||||||
| } | } | ||||||
|  |  | ||||||
| // MockAPIContext mock context for unit tests | // MockAPIContext mock context for unit tests | ||||||
| // TODO: move this function to other packages, because it depends on "models" package | // TODO: move this function to other packages, because it depends on "models" package | ||||||
| func MockAPIContext(t *testing.T, path string) *context.APIContext { | func MockAPIContext(t *testing.T, reqPath string) (*context.APIContext, *httptest.ResponseRecorder) { | ||||||
| 	resp := httptest.NewRecorder() | 	resp := httptest.NewRecorder() | ||||||
| 	requestURL, err := url.Parse(path) | 	req := mockRequest(t, reqPath) | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	req := &http.Request{ |  | ||||||
| 		URL:  requestURL, |  | ||||||
| 		Form: url.Values{}, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	base, baseCleanUp := context.NewBaseContext(resp, req) | 	base, baseCleanUp := context.NewBaseContext(resp, req) | ||||||
| 	base.Data = middleware.ContextData{} | 	base.Data = middleware.GetContextData(req.Context()) | ||||||
| 	base.Locale = &translation.MockLocale{} | 	base.Locale = &translation.MockLocale{} | ||||||
| 	ctx := &context.APIContext{Base: base} | 	ctx := &context.APIContext{Base: base} | ||||||
| 	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later | 	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later | ||||||
|  |  | ||||||
| 	chiCtx := chi.NewRouteContext() | 	chiCtx := chi.NewRouteContext() | ||||||
| 	ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) | 	ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) | ||||||
| 	return ctx | 	return ctx, resp | ||||||
| } | } | ||||||
|  |  | ||||||
| // LoadRepo load a repo into a test context. | // LoadRepo load a repo into a test context. | ||||||
|   | |||||||
| @@ -9,25 +9,15 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"reflect" | 	"reflect" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/context" |  | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/web/routing" | 	"code.gitea.io/gitea/modules/web/routing" | ||||||
|  | 	"code.gitea.io/gitea/modules/web/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ResponseStatusProvider is an interface to check whether the response has been written by the handler | var responseStatusProviders = map[reflect.Type]func(req *http.Request) types.ResponseStatusProvider{} | ||||||
| type ResponseStatusProvider interface { |  | ||||||
| 	Written() bool |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // TODO: decouple this from the context package, let the context package register these providers | func RegisterResponseStatusProvider[T any](fn func(req *http.Request) types.ResponseStatusProvider) { | ||||||
| var argTypeProvider = map[reflect.Type]func(req *http.Request) ResponseStatusProvider{ | 	responseStatusProviders[reflect.TypeOf((*T)(nil)).Elem()] = fn | ||||||
| 	reflect.TypeOf(&context.APIContext{}):     func(req *http.Request) ResponseStatusProvider { return context.GetAPIContext(req) }, |  | ||||||
| 	reflect.TypeOf(&context.Context{}):        func(req *http.Request) ResponseStatusProvider { return context.GetWebContext(req) }, |  | ||||||
| 	reflect.TypeOf(&context.PrivateContext{}): func(req *http.Request) ResponseStatusProvider { return context.GetPrivateContext(req) }, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func RegisterHandleTypeProvider[T any](fn func(req *http.Request) ResponseStatusProvider) { |  | ||||||
| 	argTypeProvider[reflect.TypeOf((*T)(nil)).Elem()] = fn |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // responseWriter is a wrapper of http.ResponseWriter, to check whether the response has been written | // responseWriter is a wrapper of http.ResponseWriter, to check whether the response has been written | ||||||
| @@ -36,10 +26,10 @@ type responseWriter struct { | |||||||
| 	status     int | 	status     int | ||||||
| } | } | ||||||
|  |  | ||||||
| var _ ResponseStatusProvider = (*responseWriter)(nil) | var _ types.ResponseStatusProvider = (*responseWriter)(nil) | ||||||
|  |  | ||||||
| func (r *responseWriter) Written() bool { | func (r *responseWriter) WrittenStatus() int { | ||||||
| 	return r.status > 0 | 	return r.status | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *responseWriter) Header() http.Header { | func (r *responseWriter) Header() http.Header { | ||||||
| @@ -68,7 +58,7 @@ var ( | |||||||
| func preCheckHandler(fn reflect.Value, argsIn []reflect.Value) { | func preCheckHandler(fn reflect.Value, argsIn []reflect.Value) { | ||||||
| 	hasStatusProvider := false | 	hasStatusProvider := false | ||||||
| 	for _, argIn := range argsIn { | 	for _, argIn := range argsIn { | ||||||
| 		if _, hasStatusProvider = argIn.Interface().(ResponseStatusProvider); hasStatusProvider { | 		if _, hasStatusProvider = argIn.Interface().(types.ResponseStatusProvider); hasStatusProvider { | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -101,7 +91,7 @@ func prepareHandleArgsIn(resp http.ResponseWriter, req *http.Request, fn reflect | |||||||
| 		case httpReqType: | 		case httpReqType: | ||||||
| 			argsIn[i] = reflect.ValueOf(req) | 			argsIn[i] = reflect.ValueOf(req) | ||||||
| 		default: | 		default: | ||||||
| 			if argFn, ok := argTypeProvider[argTyp]; ok { | 			if argFn, ok := responseStatusProviders[argTyp]; ok { | ||||||
| 				if isPreCheck { | 				if isPreCheck { | ||||||
| 					argsIn[i] = reflect.ValueOf(&responseWriter{}) | 					argsIn[i] = reflect.ValueOf(&responseWriter{}) | ||||||
| 				} else { | 				} else { | ||||||
| @@ -129,8 +119,8 @@ func handleResponse(fn reflect.Value, ret []reflect.Value) goctx.CancelFunc { | |||||||
|  |  | ||||||
| func hasResponseBeenWritten(argsIn []reflect.Value) bool { | func hasResponseBeenWritten(argsIn []reflect.Value) bool { | ||||||
| 	for _, argIn := range argsIn { | 	for _, argIn := range argsIn { | ||||||
| 		if statusProvider, ok := argIn.Interface().(ResponseStatusProvider); ok { | 		if statusProvider, ok := argIn.Interface().(types.ResponseStatusProvider); ok { | ||||||
| 			if statusProvider.Written() { | 			if statusProvider.WrittenStatus() != 0 { | ||||||
| 				return true | 				return true | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -161,7 +151,7 @@ func toHandlerProvider(handler any) func(next http.Handler) http.Handler { | |||||||
| 		return http.HandlerFunc(func(respOrig http.ResponseWriter, req *http.Request) { | 		return http.HandlerFunc(func(respOrig http.ResponseWriter, req *http.Request) { | ||||||
| 			// wrap the response writer to check whether the response has been written | 			// wrap the response writer to check whether the response has been written | ||||||
| 			resp := respOrig | 			resp := respOrig | ||||||
| 			if _, ok := resp.(ResponseStatusProvider); !ok { | 			if _, ok := resp.(types.ResponseStatusProvider); !ok { | ||||||
| 				resp = &responseWriter{respWriter: resp} | 				resp = &responseWriter{respWriter: resp} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ type ContextDataStore interface { | |||||||
|  |  | ||||||
| type ContextData map[string]any | type ContextData map[string]any | ||||||
|  |  | ||||||
| func (ds ContextData) GetData() map[string]any { | func (ds ContextData) GetData() ContextData { | ||||||
| 	return ds | 	return ds | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,31 +7,31 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/context" |  | ||||||
| 	"code.gitea.io/gitea/modules/web/middleware" | 	"code.gitea.io/gitea/modules/web/middleware" | ||||||
|  |  | ||||||
| 	"gitea.com/go-chi/binding" | 	"gitea.com/go-chi/binding" | ||||||
| 	chi "github.com/go-chi/chi/v5" | 	"github.com/go-chi/chi/v5" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Bind binding an obj to a handler | // Bind binding an obj to a handler's context data | ||||||
| func Bind[T any](_ T) any { | func Bind[T any](_ T) http.HandlerFunc { | ||||||
| 	return func(ctx *context.Context) { | 	return func(resp http.ResponseWriter, req *http.Request) { | ||||||
| 		theObj := new(T) // create a new form obj for every request but not use obj directly | 		theObj := new(T) // create a new form obj for every request but not use obj directly | ||||||
| 		binding.Bind(ctx.Req, theObj) | 		data := middleware.GetContextData(req.Context()) | ||||||
| 		SetForm(ctx, theObj) | 		binding.Bind(req, theObj) | ||||||
| 		middleware.AssignForm(theObj, ctx.Data) | 		SetForm(data, theObj) | ||||||
|  | 		middleware.AssignForm(theObj, data) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // SetForm set the form object | // SetForm set the form object | ||||||
| func SetForm(data middleware.ContextDataStore, obj interface{}) { | func SetForm(dataStore middleware.ContextDataStore, obj interface{}) { | ||||||
| 	data.GetData()["__form"] = obj | 	dataStore.GetData()["__form"] = obj | ||||||
| } | } | ||||||
|  |  | ||||||
| // GetForm returns the validate form information | // GetForm returns the validate form information | ||||||
| func GetForm(data middleware.ContextDataStore) interface{} { | func GetForm(dataStore middleware.ContextDataStore) interface{} { | ||||||
| 	return data.GetData()["__form"] | 	return dataStore.GetData()["__form"] | ||||||
| } | } | ||||||
|  |  | ||||||
| // Route defines a route based on chi's router | // Route defines a route based on chi's router | ||||||
|   | |||||||
| @@ -8,8 +8,8 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/context" |  | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
|  | 	"code.gitea.io/gitea/modules/web/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // NewLoggerHandler is a handler that will log routing to the router log taking account of | // NewLoggerHandler is a handler that will log routing to the router log taking account of | ||||||
| @@ -86,8 +86,8 @@ func logPrinter(logger log.Logger) func(trigger Event, record *requestRecord) { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		var status int | 		var status int | ||||||
| 		if v, ok := record.responseWriter.(context.ResponseWriter); ok { | 		if v, ok := record.responseWriter.(types.ResponseStatusProvider); ok { | ||||||
| 			status = v.Status() | 			status = v.WrittenStatus() | ||||||
| 		} | 		} | ||||||
| 		logf := log.Info | 		logf := log.Info | ||||||
| 		if strings.HasPrefix(req.RequestURI, "/assets/") { | 		if strings.HasPrefix(req.RequestURI, "/assets/") { | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								modules/web/types/response.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								modules/web/types/response.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | // Copyright 2023 The Gitea Authors. All rights reserved. | ||||||
|  | // SPDX-License-Identifier: MIT | ||||||
|  |  | ||||||
|  | package types | ||||||
|  |  | ||||||
|  | // ResponseStatusProvider is an interface to get the written status in the response | ||||||
|  | // Many packages need this interface, so put it in the separate package to avoid import cycle | ||||||
|  | type ResponseStatusProvider interface { | ||||||
|  | 	WrittenStatus() int | ||||||
|  | } | ||||||
| @@ -4,7 +4,6 @@ | |||||||
| package actions | package actions | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/web" | 	"code.gitea.io/gitea/modules/web" | ||||||
| @@ -12,7 +11,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/routers/api/actions/runner" | 	"code.gitea.io/gitea/routers/api/actions/runner" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Routes(_ context.Context, prefix string) *web.Route { | func Routes(prefix string) *web.Route { | ||||||
| 	m := web.NewRoute() | 	m := web.NewRoute() | ||||||
|  |  | ||||||
| 	path, handler := ping.NewPingServiceHandler() | 	path, handler := ping.NewPingServiceHandler() | ||||||
|   | |||||||
| @@ -82,6 +82,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/storage" | 	"code.gitea.io/gitea/modules/storage" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
| 	"code.gitea.io/gitea/modules/web" | 	"code.gitea.io/gitea/modules/web" | ||||||
|  | 	web_types "code.gitea.io/gitea/modules/web/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -102,7 +103,7 @@ type ArtifactContext struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
| 	web.RegisterHandleTypeProvider[*ArtifactContext](func(req *http.Request) web.ResponseStatusProvider { | 	web.RegisterResponseStatusProvider[*ArtifactContext](func(req *http.Request) web_types.ResponseStatusProvider { | ||||||
| 		return req.Context().Value(artifactContextKey).(*ArtifactContext) | 		return req.Context().Value(artifactContextKey).(*ArtifactContext) | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ | |||||||
| package packages | package packages | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	gocontext "context" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -96,7 +95,7 @@ func verifyAuth(r *web.Route, authMethods []auth.Method) { | |||||||
|  |  | ||||||
| // CommonRoutes provide endpoints for most package managers (except containers - see below) | // CommonRoutes provide endpoints for most package managers (except containers - see below) | ||||||
| // These are mounted on `/api/packages` (not `/api/v1/packages`) | // These are mounted on `/api/packages` (not `/api/v1/packages`) | ||||||
| func CommonRoutes(ctx gocontext.Context) *web.Route { | func CommonRoutes() *web.Route { | ||||||
| 	r := web.NewRoute() | 	r := web.NewRoute() | ||||||
|  |  | ||||||
| 	r.Use(context.PackageContexter()) | 	r.Use(context.PackageContexter()) | ||||||
| @@ -590,7 +589,7 @@ func CommonRoutes(ctx gocontext.Context) *web.Route { | |||||||
| // ContainerRoutes provides endpoints that implement the OCI API to serve containers | // ContainerRoutes provides endpoints that implement the OCI API to serve containers | ||||||
| // These have to be mounted on `/v2/...` to comply with the OCI spec: | // These have to be mounted on `/v2/...` to comply with the OCI spec: | ||||||
| // https://github.com/opencontainers/distribution-spec/blob/main/spec.md | // https://github.com/opencontainers/distribution-spec/blob/main/spec.md | ||||||
| func ContainerRoutes(ctx gocontext.Context) *web.Route { | func ContainerRoutes() *web.Route { | ||||||
| 	r := web.NewRoute() | 	r := web.NewRoute() | ||||||
|  |  | ||||||
| 	r.Use(context.PackageContexter()) | 	r.Use(context.PackageContexter()) | ||||||
|   | |||||||
| @@ -64,7 +64,6 @@ | |||||||
| package v1 | package v1 | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	gocontext "context" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -705,7 +704,7 @@ func buildAuthGroup() *auth.Group { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Routes registers all v1 APIs routes to web application. | // Routes registers all v1 APIs routes to web application. | ||||||
| func Routes(ctx gocontext.Context) *web.Route { | func Routes() *web.Route { | ||||||
| 	m := web.NewRoute() | 	m := web.NewRoute() | ||||||
|  |  | ||||||
| 	m.Use(securityHeaders()) | 	m.Use(securityHeaders()) | ||||||
| @@ -722,13 +721,8 @@ func Routes(ctx gocontext.Context) *web.Route { | |||||||
| 	} | 	} | ||||||
| 	m.Use(context.APIContexter()) | 	m.Use(context.APIContexter()) | ||||||
|  |  | ||||||
| 	group := buildAuthGroup() |  | ||||||
| 	if err := group.Init(ctx); err != nil { |  | ||||||
| 		log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Get user from session if logged in. | 	// Get user from session if logged in. | ||||||
| 	m.Use(auth.APIAuth(group)) | 	m.Use(auth.APIAuth(buildAuthGroup())) | ||||||
|  |  | ||||||
| 	m.Use(auth.VerifyAuthWithOptionsAPI(&auth.VerifyOptions{ | 	m.Use(auth.VerifyAuthWithOptionsAPI(&auth.VerifyOptions{ | ||||||
| 		SignInRequired: setting.Service.RequireSignInView, | 		SignInRequired: setting.Service.RequireSignInView, | ||||||
|   | |||||||
| @@ -7,18 +7,14 @@ import ( | |||||||
| 	go_context "context" | 	go_context "context" | ||||||
| 	"io" | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" |  | ||||||
| 	"net/url" |  | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/context" |  | ||||||
| 	"code.gitea.io/gitea/modules/markup" | 	"code.gitea.io/gitea/modules/markup" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	api "code.gitea.io/gitea/modules/structs" | 	api "code.gitea.io/gitea/modules/structs" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/test" | ||||||
| 	"code.gitea.io/gitea/modules/web" | 	"code.gitea.io/gitea/modules/web" | ||||||
| 	"code.gitea.io/gitea/modules/web/middleware" |  | ||||||
|  |  | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
| @@ -29,34 +25,16 @@ const ( | |||||||
| 	AppSubURL = AppURL + Repo + "/" | 	AppSubURL = AppURL + Repo + "/" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func createAPIContext(req *http.Request) (*context.APIContext, *httptest.ResponseRecorder) { |  | ||||||
| 	resp := httptest.NewRecorder() |  | ||||||
| 	base, baseCleanUp := context.NewBaseContext(resp, req) |  | ||||||
| 	base.Data = middleware.ContextData{} |  | ||||||
| 	c := &context.APIContext{Base: base} |  | ||||||
| 	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later |  | ||||||
|  |  | ||||||
| 	return c, resp |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, responseCode int) { | func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, responseCode int) { | ||||||
| 	setting.AppURL = AppURL | 	setting.AppURL = AppURL | ||||||
|  |  | ||||||
| 	options := api.MarkupOption{ | 	options := api.MarkupOption{ | ||||||
| 		Mode:     mode, | 		Mode:     mode, | ||||||
| 		Text:     "", | 		Text:     text, | ||||||
| 		Context:  Repo, | 		Context:  Repo, | ||||||
| 		Wiki:     true, | 		Wiki:     true, | ||||||
| 		FilePath: filePath, | 		FilePath: filePath, | ||||||
| 	} | 	} | ||||||
| 	requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markup")) | 	ctx, resp := test.MockAPIContext(t, "POST /api/v1/markup") | ||||||
| 	req := &http.Request{ |  | ||||||
| 		Method: "POST", |  | ||||||
| 		URL:    requrl, |  | ||||||
| 	} |  | ||||||
| 	ctx, resp := createAPIContext(req) |  | ||||||
|  |  | ||||||
| 	options.Text = text |  | ||||||
| 	web.SetForm(ctx, &options) | 	web.SetForm(ctx, &options) | ||||||
| 	Markup(ctx) | 	Markup(ctx) | ||||||
| 	assert.Equal(t, responseBody, resp.Body.String()) | 	assert.Equal(t, responseBody, resp.Body.String()) | ||||||
| @@ -66,21 +44,13 @@ func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, r | |||||||
|  |  | ||||||
| func testRenderMarkdown(t *testing.T, mode, text, responseBody string, responseCode int) { | func testRenderMarkdown(t *testing.T, mode, text, responseBody string, responseCode int) { | ||||||
| 	setting.AppURL = AppURL | 	setting.AppURL = AppURL | ||||||
|  |  | ||||||
| 	options := api.MarkdownOption{ | 	options := api.MarkdownOption{ | ||||||
| 		Mode:    mode, | 		Mode:    mode, | ||||||
| 		Text:    "", | 		Text:    text, | ||||||
| 		Context: Repo, | 		Context: Repo, | ||||||
| 		Wiki:    true, | 		Wiki:    true, | ||||||
| 	} | 	} | ||||||
| 	requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) | 	ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") | ||||||
| 	req := &http.Request{ |  | ||||||
| 		Method: "POST", |  | ||||||
| 		URL:    requrl, |  | ||||||
| 	} |  | ||||||
| 	ctx, resp := createAPIContext(req) |  | ||||||
|  |  | ||||||
| 	options.Text = text |  | ||||||
| 	web.SetForm(ctx, &options) | 	web.SetForm(ctx, &options) | ||||||
| 	Markdown(ctx) | 	Markdown(ctx) | ||||||
| 	assert.Equal(t, responseBody, resp.Body.String()) | 	assert.Equal(t, responseBody, resp.Body.String()) | ||||||
| @@ -187,19 +157,12 @@ var simpleCases = []string{ | |||||||
|  |  | ||||||
| func TestAPI_RenderSimple(t *testing.T) { | func TestAPI_RenderSimple(t *testing.T) { | ||||||
| 	setting.AppURL = AppURL | 	setting.AppURL = AppURL | ||||||
|  |  | ||||||
| 	options := api.MarkdownOption{ | 	options := api.MarkdownOption{ | ||||||
| 		Mode:    "markdown", | 		Mode:    "markdown", | ||||||
| 		Text:    "", | 		Text:    "", | ||||||
| 		Context: Repo, | 		Context: Repo, | ||||||
| 	} | 	} | ||||||
| 	requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) | 	ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") | ||||||
| 	req := &http.Request{ |  | ||||||
| 		Method: "POST", |  | ||||||
| 		URL:    requrl, |  | ||||||
| 	} |  | ||||||
| 	ctx, resp := createAPIContext(req) |  | ||||||
|  |  | ||||||
| 	for i := 0; i < len(simpleCases); i += 2 { | 	for i := 0; i < len(simpleCases); i += 2 { | ||||||
| 		options.Text = simpleCases[i] | 		options.Text = simpleCases[i] | ||||||
| 		web.SetForm(ctx, &options) | 		web.SetForm(ctx, &options) | ||||||
| @@ -211,14 +174,7 @@ func TestAPI_RenderSimple(t *testing.T) { | |||||||
|  |  | ||||||
| func TestAPI_RenderRaw(t *testing.T) { | func TestAPI_RenderRaw(t *testing.T) { | ||||||
| 	setting.AppURL = AppURL | 	setting.AppURL = AppURL | ||||||
|  | 	ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") | ||||||
| 	requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) |  | ||||||
| 	req := &http.Request{ |  | ||||||
| 		Method: "POST", |  | ||||||
| 		URL:    requrl, |  | ||||||
| 	} |  | ||||||
| 	ctx, resp := createAPIContext(req) |  | ||||||
|  |  | ||||||
| 	for i := 0; i < len(simpleCases); i += 2 { | 	for i := 0; i < len(simpleCases); i += 2 { | ||||||
| 		ctx.Req.Body = io.NopCloser(strings.NewReader(simpleCases[i])) | 		ctx.Req.Body = io.NopCloser(strings.NewReader(simpleCases[i])) | ||||||
| 		MarkdownRaw(ctx) | 		MarkdownRaw(ctx) | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ import ( | |||||||
| func TestTestHook(t *testing.T) { | func TestTestHook(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockAPIContext(t, "user2/repo1/wiki/_pages") | 	ctx, _ := test.MockAPIContext(t, "user2/repo1/wiki/_pages") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import ( | |||||||
| func TestRepoEdit(t *testing.T) { | func TestRepoEdit(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockAPIContext(t, "user2/repo1") | 	ctx, _ := test.MockAPIContext(t, "user2/repo1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	ctx.Repo.Owner = ctx.Doer | 	ctx.Repo.Owner = ctx.Doer | ||||||
| @@ -65,7 +65,7 @@ func TestRepoEdit(t *testing.T) { | |||||||
| func TestRepoEditNameChange(t *testing.T) { | func TestRepoEditNameChange(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockAPIContext(t, "user2/repo1") | 	ctx, _ := test.MockAPIContext(t, "user2/repo1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	ctx.Repo.Owner = ctx.Doer | 	ctx.Repo.Owner = ctx.Doer | ||||||
|   | |||||||
| @@ -174,27 +174,27 @@ func GlobalInitInstalled(ctx context.Context) { | |||||||
| } | } | ||||||
|  |  | ||||||
| // NormalRoutes represents non install routes | // NormalRoutes represents non install routes | ||||||
| func NormalRoutes(ctx context.Context) *web.Route { | func NormalRoutes() *web.Route { | ||||||
| 	_ = templates.HTMLRenderer() | 	_ = templates.HTMLRenderer() | ||||||
| 	r := web.NewRoute() | 	r := web.NewRoute() | ||||||
| 	r.Use(common.ProtocolMiddlewares()...) | 	r.Use(common.ProtocolMiddlewares()...) | ||||||
|  |  | ||||||
| 	r.Mount("/", web_routers.Routes(ctx)) | 	r.Mount("/", web_routers.Routes()) | ||||||
| 	r.Mount("/api/v1", apiv1.Routes(ctx)) | 	r.Mount("/api/v1", apiv1.Routes()) | ||||||
| 	r.Mount("/api/internal", private.Routes()) | 	r.Mount("/api/internal", private.Routes()) | ||||||
|  |  | ||||||
| 	r.Post("/-/fetch-redirect", common.FetchRedirectDelegate) | 	r.Post("/-/fetch-redirect", common.FetchRedirectDelegate) | ||||||
|  |  | ||||||
| 	if setting.Packages.Enabled { | 	if setting.Packages.Enabled { | ||||||
| 		// This implements package support for most package managers | 		// This implements package support for most package managers | ||||||
| 		r.Mount("/api/packages", packages_router.CommonRoutes(ctx)) | 		r.Mount("/api/packages", packages_router.CommonRoutes()) | ||||||
| 		// This implements the OCI API (Note this is not preceded by /api but is instead /v2) | 		// This implements the OCI API (Note this is not preceded by /api but is instead /v2) | ||||||
| 		r.Mount("/v2", packages_router.ContainerRoutes(ctx)) | 		r.Mount("/v2", packages_router.ContainerRoutes()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if setting.Actions.Enabled { | 	if setting.Actions.Enabled { | ||||||
| 		prefix := "/api/actions" | 		prefix := "/api/actions" | ||||||
| 		r.Mount(prefix, actions_router.Routes(ctx, prefix)) | 		r.Mount(prefix, actions_router.Routes(prefix)) | ||||||
|  |  | ||||||
| 		// TODO: Pipeline api used for runner internal communication with gitea server. but only artifact is used for now. | 		// TODO: Pipeline api used for runner internal communication with gitea server. but only artifact is used for now. | ||||||
| 		// In Github, it uses ACTIONS_RUNTIME_URL=https://pipelines.actions.githubusercontent.com/fLgcSHkPGySXeIFrg8W8OBSfeg3b5Fls1A1CwX566g8PayEGlg/ | 		// In Github, it uses ACTIONS_RUNTIME_URL=https://pipelines.actions.githubusercontent.com/fLgcSHkPGySXeIFrg8W8OBSfeg3b5Fls1A1CwX566g8PayEGlg/ | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import ( | |||||||
|  |  | ||||||
| func TestNewUserPost_MustChangePassword(t *testing.T) { | func TestNewUserPost_MustChangePassword(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "admin/users/new") | 	ctx, _ := test.MockContext(t, "admin/users/new") | ||||||
|  |  | ||||||
| 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | ||||||
| 		IsAdmin: true, | 		IsAdmin: true, | ||||||
| @@ -56,7 +56,7 @@ func TestNewUserPost_MustChangePassword(t *testing.T) { | |||||||
|  |  | ||||||
| func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { | func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "admin/users/new") | 	ctx, _ := test.MockContext(t, "admin/users/new") | ||||||
|  |  | ||||||
| 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | ||||||
| 		IsAdmin: true, | 		IsAdmin: true, | ||||||
| @@ -93,7 +93,7 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { | |||||||
|  |  | ||||||
| func TestNewUserPost_InvalidEmail(t *testing.T) { | func TestNewUserPost_InvalidEmail(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "admin/users/new") | 	ctx, _ := test.MockContext(t, "admin/users/new") | ||||||
|  |  | ||||||
| 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | ||||||
| 		IsAdmin: true, | 		IsAdmin: true, | ||||||
| @@ -123,7 +123,7 @@ func TestNewUserPost_InvalidEmail(t *testing.T) { | |||||||
|  |  | ||||||
| func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { | func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "admin/users/new") | 	ctx, _ := test.MockContext(t, "admin/users/new") | ||||||
|  |  | ||||||
| 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | ||||||
| 		IsAdmin: true, | 		IsAdmin: true, | ||||||
| @@ -161,7 +161,7 @@ func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { | |||||||
|  |  | ||||||
| func TestNewUserPost_VisibilityPrivate(t *testing.T) { | func TestNewUserPost_VisibilityPrivate(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "admin/users/new") | 	ctx, _ := test.MockContext(t, "admin/users/new") | ||||||
|  |  | ||||||
| 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | 	u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | ||||||
| 		IsAdmin: true, | 		IsAdmin: true, | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ import ( | |||||||
|  |  | ||||||
| func TestCheckProjectBoardChangePermissions(t *testing.T) { | func TestCheckProjectBoardChangePermissions(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/-/projects/4/4") | 	ctx, _ := test.MockContext(t, "user2/-/projects/4/4") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	ctx.ContextUser = ctx.Doer // user2 | 	ctx.ContextUser = ctx.Doer // user2 | ||||||
| 	ctx.SetParams(":id", "4") | 	ctx.SetParams(":id", "4") | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ func TestCleanUploadName(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetUniquePatchBranchName(t *testing.T) { | func TestGetUniquePatchBranchName(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -56,7 +56,7 @@ func TestGetUniquePatchBranchName(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetClosestParentWithFiles(t *testing.T) { | func TestGetClosestParentWithFiles(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ func int64SliceToCommaSeparated(a []int64) string { | |||||||
| func TestInitializeLabels(t *testing.T) { | func TestInitializeLabels(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	assert.NoError(t, repository.LoadRepoConfig()) | 	assert.NoError(t, repository.LoadRepoConfig()) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/labels/initialize") | 	ctx, _ := test.MockContext(t, "user2/repo1/labels/initialize") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 2) | 	test.LoadRepo(t, ctx, 2) | ||||||
| 	web.SetForm(ctx, &forms.InitializeLabelsForm{TemplateName: "Default"}) | 	web.SetForm(ctx, &forms.InitializeLabelsForm{TemplateName: "Default"}) | ||||||
| @@ -57,7 +57,7 @@ func TestRetrieveLabels(t *testing.T) { | |||||||
| 		{1, "leastissues", []int64{2, 1}}, | 		{1, "leastissues", []int64{2, 1}}, | ||||||
| 		{2, "", []int64{}}, | 		{2, "", []int64{}}, | ||||||
| 	} { | 	} { | ||||||
| 		ctx := test.MockContext(t, "user/repo/issues") | 		ctx, _ := test.MockContext(t, "user/repo/issues") | ||||||
| 		test.LoadUser(t, ctx, 2) | 		test.LoadUser(t, ctx, 2) | ||||||
| 		test.LoadRepo(t, ctx, testCase.RepoID) | 		test.LoadRepo(t, ctx, testCase.RepoID) | ||||||
| 		ctx.Req.Form.Set("sort", testCase.Sort) | 		ctx.Req.Form.Set("sort", testCase.Sort) | ||||||
| @@ -75,7 +75,7 @@ func TestRetrieveLabels(t *testing.T) { | |||||||
|  |  | ||||||
| func TestNewLabel(t *testing.T) { | func TestNewLabel(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/labels/edit") | 	ctx, _ := test.MockContext(t, "user2/repo1/labels/edit") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	web.SetForm(ctx, &forms.CreateLabelForm{ | 	web.SetForm(ctx, &forms.CreateLabelForm{ | ||||||
| @@ -93,7 +93,7 @@ func TestNewLabel(t *testing.T) { | |||||||
|  |  | ||||||
| func TestUpdateLabel(t *testing.T) { | func TestUpdateLabel(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/labels/edit") | 	ctx, _ := test.MockContext(t, "user2/repo1/labels/edit") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	web.SetForm(ctx, &forms.CreateLabelForm{ | 	web.SetForm(ctx, &forms.CreateLabelForm{ | ||||||
| @@ -113,7 +113,7 @@ func TestUpdateLabel(t *testing.T) { | |||||||
|  |  | ||||||
| func TestDeleteLabel(t *testing.T) { | func TestDeleteLabel(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/labels/delete") | 	ctx, _ := test.MockContext(t, "user2/repo1/labels/delete") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	ctx.Req.Form.Set("id", "2") | 	ctx.Req.Form.Set("id", "2") | ||||||
| @@ -126,7 +126,7 @@ func TestDeleteLabel(t *testing.T) { | |||||||
|  |  | ||||||
| func TestUpdateIssueLabel_Clear(t *testing.T) { | func TestUpdateIssueLabel_Clear(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/issues/labels") | 	ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	ctx.Req.Form.Set("issue_ids", "1,3") | 	ctx.Req.Form.Set("issue_ids", "1,3") | ||||||
| @@ -151,7 +151,7 @@ func TestUpdateIssueLabel_Toggle(t *testing.T) { | |||||||
| 		{"toggle", []int64{1, 2}, 2, true}, | 		{"toggle", []int64{1, 2}, 2, true}, | ||||||
| 	} { | 	} { | ||||||
| 		unittest.PrepareTestEnv(t) | 		unittest.PrepareTestEnv(t) | ||||||
| 		ctx := test.MockContext(t, "user2/repo1/issues/labels") | 		ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | ||||||
| 		test.LoadUser(t, ctx, 2) | 		test.LoadUser(t, ctx, 2) | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| 		ctx.Req.Form.Set("issue_ids", int64SliceToCommaSeparated(testCase.IssueIDs)) | 		ctx.Req.Form.Set("issue_ids", int64SliceToCommaSeparated(testCase.IssueIDs)) | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ import ( | |||||||
|  |  | ||||||
| func TestCheckProjectBoardChangePermissions(t *testing.T) { | func TestCheckProjectBoardChangePermissions(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/projects/1/2") | 	ctx, _ := test.MockContext(t, "user2/repo1/projects/1/2") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ func TestNewReleasePost(t *testing.T) { | |||||||
| 	} { | 	} { | ||||||
| 		unittest.PrepareTestEnv(t) | 		unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 		ctx := test.MockContext(t, "user2/repo1/releases/new") | 		ctx, _ := test.MockContext(t, "user2/repo1/releases/new") | ||||||
| 		test.LoadUser(t, ctx, 2) | 		test.LoadUser(t, ctx, 2) | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| 		test.LoadGitRepo(t, ctx) | 		test.LoadGitRepo(t, ctx) | ||||||
| @@ -67,7 +67,7 @@ func TestNewReleasePost(t *testing.T) { | |||||||
|  |  | ||||||
| func TestNewReleasesList(t *testing.T) { | func TestNewReleasesList(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo-release/releases") | 	ctx, _ := test.MockContext(t, "user2/repo-release/releases") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 57) | 	test.LoadRepo(t, ctx, 57) | ||||||
| 	test.LoadGitRepo(t, ctx) | 	test.LoadGitRepo(t, ctx) | ||||||
|   | |||||||
| @@ -42,7 +42,7 @@ func TestAddReadOnlyDeployKey(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/settings/keys") | 	ctx, _ := test.MockContext(t, "user2/repo1/settings/keys") | ||||||
|  |  | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 2) | 	test.LoadRepo(t, ctx, 2) | ||||||
| @@ -71,7 +71,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) { | |||||||
|  |  | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/settings/keys") | 	ctx, _ := test.MockContext(t, "user2/repo1/settings/keys") | ||||||
|  |  | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 2) | 	test.LoadRepo(t, ctx, 2) | ||||||
| @@ -94,7 +94,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) { | |||||||
|  |  | ||||||
| func TestCollaborationPost(t *testing.T) { | func TestCollaborationPost(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/issues/labels") | 	ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadUser(t, ctx, 4) | 	test.LoadUser(t, ctx, 4) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| @@ -129,7 +129,7 @@ func TestCollaborationPost(t *testing.T) { | |||||||
|  |  | ||||||
| func TestCollaborationPost_InactiveUser(t *testing.T) { | func TestCollaborationPost_InactiveUser(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/issues/labels") | 	ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadUser(t, ctx, 9) | 	test.LoadUser(t, ctx, 9) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| @@ -152,7 +152,7 @@ func TestCollaborationPost_InactiveUser(t *testing.T) { | |||||||
|  |  | ||||||
| func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { | func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/issues/labels") | 	ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadUser(t, ctx, 4) | 	test.LoadUser(t, ctx, 4) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| @@ -193,7 +193,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { | |||||||
|  |  | ||||||
| func TestCollaborationPost_NonExistentUser(t *testing.T) { | func TestCollaborationPost_NonExistentUser(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/issues/labels") | 	ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
|  |  | ||||||
| @@ -215,7 +215,7 @@ func TestCollaborationPost_NonExistentUser(t *testing.T) { | |||||||
|  |  | ||||||
| func TestAddTeamPost(t *testing.T) { | func TestAddTeamPost(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "org26/repo43") | 	ctx, _ := test.MockContext(t, "org26/repo43") | ||||||
|  |  | ||||||
| 	ctx.Req.Form.Set("team", "team11") | 	ctx.Req.Form.Set("team", "team11") | ||||||
|  |  | ||||||
| @@ -255,7 +255,7 @@ func TestAddTeamPost(t *testing.T) { | |||||||
|  |  | ||||||
| func TestAddTeamPost_NotAllowed(t *testing.T) { | func TestAddTeamPost_NotAllowed(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "org26/repo43") | 	ctx, _ := test.MockContext(t, "org26/repo43") | ||||||
|  |  | ||||||
| 	ctx.Req.Form.Set("team", "team11") | 	ctx.Req.Form.Set("team", "team11") | ||||||
|  |  | ||||||
| @@ -295,7 +295,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) { | |||||||
|  |  | ||||||
| func TestAddTeamPost_AddTeamTwice(t *testing.T) { | func TestAddTeamPost_AddTeamTwice(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "org26/repo43") | 	ctx, _ := test.MockContext(t, "org26/repo43") | ||||||
|  |  | ||||||
| 	ctx.Req.Form.Set("team", "team11") | 	ctx.Req.Form.Set("team", "team11") | ||||||
|  |  | ||||||
| @@ -336,7 +336,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) { | |||||||
|  |  | ||||||
| func TestAddTeamPost_NonExistentTeam(t *testing.T) { | func TestAddTeamPost_NonExistentTeam(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "org26/repo43") | 	ctx, _ := test.MockContext(t, "org26/repo43") | ||||||
|  |  | ||||||
| 	ctx.Req.Form.Set("team", "team-non-existent") | 	ctx.Req.Form.Set("team", "team-non-existent") | ||||||
|  |  | ||||||
| @@ -369,7 +369,7 @@ func TestAddTeamPost_NonExistentTeam(t *testing.T) { | |||||||
|  |  | ||||||
| func TestDeleteTeam(t *testing.T) { | func TestDeleteTeam(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "org3/team1/repo3") | 	ctx, _ := test.MockContext(t, "org3/team1/repo3") | ||||||
|  |  | ||||||
| 	ctx.Req.Form.Set("id", "2") | 	ctx.Req.Form.Set("id", "2") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -78,7 +78,7 @@ func assertPagesMetas(t *testing.T, expectedNames []string, metas interface{}) { | |||||||
| func TestWiki(t *testing.T) { | func TestWiki(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages") | 	ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_pages") | ||||||
| 	ctx.SetParams("*", "Home") | 	ctx.SetParams("*", "Home") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	Wiki(ctx) | 	Wiki(ctx) | ||||||
| @@ -90,7 +90,7 @@ func TestWiki(t *testing.T) { | |||||||
| func TestWikiPages(t *testing.T) { | func TestWikiPages(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages") | 	ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_pages") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	WikiPages(ctx) | 	WikiPages(ctx) | ||||||
| 	assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | 	assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | ||||||
| @@ -100,7 +100,7 @@ func TestWikiPages(t *testing.T) { | |||||||
| func TestNewWiki(t *testing.T) { | func TestNewWiki(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") | 	ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	NewWiki(ctx) | 	NewWiki(ctx) | ||||||
| @@ -115,7 +115,7 @@ func TestNewWikiPost(t *testing.T) { | |||||||
| 	} { | 	} { | ||||||
| 		unittest.PrepareTestEnv(t) | 		unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 		ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") | 		ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") | ||||||
| 		test.LoadUser(t, ctx, 2) | 		test.LoadUser(t, ctx, 2) | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| 		web.SetForm(ctx, &forms.NewWikiForm{ | 		web.SetForm(ctx, &forms.NewWikiForm{ | ||||||
| @@ -133,7 +133,7 @@ func TestNewWikiPost(t *testing.T) { | |||||||
| func TestNewWikiPost_ReservedName(t *testing.T) { | func TestNewWikiPost_ReservedName(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") | 	ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	web.SetForm(ctx, &forms.NewWikiForm{ | 	web.SetForm(ctx, &forms.NewWikiForm{ | ||||||
| @@ -150,7 +150,7 @@ func TestNewWikiPost_ReservedName(t *testing.T) { | |||||||
| func TestEditWiki(t *testing.T) { | func TestEditWiki(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit") | 	ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit") | ||||||
| 	ctx.SetParams("*", "Home") | 	ctx.SetParams("*", "Home") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| @@ -166,7 +166,7 @@ func TestEditWikiPost(t *testing.T) { | |||||||
| 		"New/<page>", | 		"New/<page>", | ||||||
| 	} { | 	} { | ||||||
| 		unittest.PrepareTestEnv(t) | 		unittest.PrepareTestEnv(t) | ||||||
| 		ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_new") | 		ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_new") | ||||||
| 		ctx.SetParams("*", "Home") | 		ctx.SetParams("*", "Home") | ||||||
| 		test.LoadUser(t, ctx, 2) | 		test.LoadUser(t, ctx, 2) | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| @@ -188,7 +188,7 @@ func TestEditWikiPost(t *testing.T) { | |||||||
| func TestDeleteWikiPagePost(t *testing.T) { | func TestDeleteWikiPagePost(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete") | 	ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	DeleteWikiPagePost(ctx) | 	DeleteWikiPagePost(ctx) | ||||||
| @@ -207,7 +207,7 @@ func TestWikiRaw(t *testing.T) { | |||||||
| 	} { | 	} { | ||||||
| 		unittest.PrepareTestEnv(t) | 		unittest.PrepareTestEnv(t) | ||||||
|  |  | ||||||
| 		ctx := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath)) | 		ctx, _ := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath)) | ||||||
| 		ctx.SetParams("*", filepath) | 		ctx.SetParams("*", filepath) | ||||||
| 		test.LoadUser(t, ctx, 2) | 		test.LoadUser(t, ctx, 2) | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ func TestArchivedIssues(t *testing.T) { | |||||||
| 	setting.UI.IssuePagingNum = 1 | 	setting.UI.IssuePagingNum = 1 | ||||||
| 	assert.NoError(t, unittest.LoadFixtures()) | 	assert.NoError(t, unittest.LoadFixtures()) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "issues") | 	ctx, _ := test.MockContext(t, "issues") | ||||||
| 	test.LoadUser(t, ctx, 30) | 	test.LoadUser(t, ctx, 30) | ||||||
| 	ctx.Req.Form.Set("state", "open") | 	ctx.Req.Form.Set("state", "open") | ||||||
|  |  | ||||||
| @@ -53,7 +53,7 @@ func TestIssues(t *testing.T) { | |||||||
| 	setting.UI.IssuePagingNum = 1 | 	setting.UI.IssuePagingNum = 1 | ||||||
| 	assert.NoError(t, unittest.LoadFixtures()) | 	assert.NoError(t, unittest.LoadFixtures()) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "issues") | 	ctx, _ := test.MockContext(t, "issues") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	ctx.Req.Form.Set("state", "closed") | 	ctx.Req.Form.Set("state", "closed") | ||||||
| 	Issues(ctx) | 	Issues(ctx) | ||||||
| @@ -69,7 +69,7 @@ func TestPulls(t *testing.T) { | |||||||
| 	setting.UI.IssuePagingNum = 20 | 	setting.UI.IssuePagingNum = 20 | ||||||
| 	assert.NoError(t, unittest.LoadFixtures()) | 	assert.NoError(t, unittest.LoadFixtures()) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "pulls") | 	ctx, _ := test.MockContext(t, "pulls") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	ctx.Req.Form.Set("state", "open") | 	ctx.Req.Form.Set("state", "open") | ||||||
| 	Pulls(ctx) | 	Pulls(ctx) | ||||||
| @@ -82,7 +82,7 @@ func TestMilestones(t *testing.T) { | |||||||
| 	setting.UI.IssuePagingNum = 1 | 	setting.UI.IssuePagingNum = 1 | ||||||
| 	assert.NoError(t, unittest.LoadFixtures()) | 	assert.NoError(t, unittest.LoadFixtures()) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "milestones") | 	ctx, _ := test.MockContext(t, "milestones") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	ctx.SetParams("sort", "issues") | 	ctx.SetParams("sort", "issues") | ||||||
| 	ctx.Req.Form.Set("state", "closed") | 	ctx.Req.Form.Set("state", "closed") | ||||||
| @@ -101,7 +101,7 @@ func TestMilestonesForSpecificRepo(t *testing.T) { | |||||||
| 	setting.UI.IssuePagingNum = 1 | 	setting.UI.IssuePagingNum = 1 | ||||||
| 	assert.NoError(t, unittest.LoadFixtures()) | 	assert.NoError(t, unittest.LoadFixtures()) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "milestones") | 	ctx, _ := test.MockContext(t, "milestones") | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
| 	ctx.SetParams("sort", "issues") | 	ctx.SetParams("sort", "issues") | ||||||
| 	ctx.SetParams("repo", "1") | 	ctx.SetParams("repo", "1") | ||||||
|   | |||||||
| @@ -83,7 +83,7 @@ func TestChangePassword(t *testing.T) { | |||||||
| 		t.Run(req.OldPassword+"__"+req.NewPassword, func(t *testing.T) { | 		t.Run(req.OldPassword+"__"+req.NewPassword, func(t *testing.T) { | ||||||
| 			unittest.PrepareTestEnv(t) | 			unittest.PrepareTestEnv(t) | ||||||
| 			setting.PasswordComplexity = req.PasswordComplexity | 			setting.PasswordComplexity = req.PasswordComplexity | ||||||
| 			ctx := test.MockContext(t, "user/settings/security") | 			ctx, _ := test.MockContext(t, "user/settings/security") | ||||||
| 			test.LoadUser(t, ctx, 2) | 			test.LoadUser(t, ctx, 2) | ||||||
| 			test.LoadRepo(t, ctx, 1) | 			test.LoadRepo(t, ctx, 1) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -104,7 +104,7 @@ func ctxDataSet(args ...any) func(ctx *context.Context) { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Routes returns all web routes | // Routes returns all web routes | ||||||
| func Routes(ctx gocontext.Context) *web.Route { | func Routes() *web.Route { | ||||||
| 	routes := web.NewRoute() | 	routes := web.NewRoute() | ||||||
|  |  | ||||||
| 	routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler | 	routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler | ||||||
| @@ -146,13 +146,8 @@ func Routes(ctx gocontext.Context) *web.Route { | |||||||
|  |  | ||||||
| 	mid = append(mid, common.Sessioner(), context.Contexter()) | 	mid = append(mid, common.Sessioner(), context.Contexter()) | ||||||
|  |  | ||||||
| 	group := buildAuthGroup() |  | ||||||
| 	if err := group.Init(ctx); err != nil { |  | ||||||
| 		log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Get user from session if logged in. | 	// Get user from session if logged in. | ||||||
| 	mid = append(mid, auth_service.Auth(group)) | 	mid = append(mid, auth_service.Auth(buildAuthGroup())) | ||||||
|  |  | ||||||
| 	// GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route | 	// GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route | ||||||
| 	mid = append(mid, middleware.GetHead) | 	mid = append(mid, middleware.GetHead) | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ | |||||||
| package auth | package auth | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -14,9 +13,7 @@ import ( | |||||||
|  |  | ||||||
| // Ensure the struct implements the interface. | // Ensure the struct implements the interface. | ||||||
| var ( | var ( | ||||||
| 	_ Method        = &Group{} | 	_ Method = &Group{} | ||||||
| 	_ Initializable = &Group{} |  | ||||||
| 	_ Freeable      = &Group{} |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Group implements the Auth interface with serval Auth. | // Group implements the Auth interface with serval Auth. | ||||||
| @@ -49,35 +46,6 @@ func (b *Group) Name() string { | |||||||
| 	return strings.Join(names, ",") | 	return strings.Join(names, ",") | ||||||
| } | } | ||||||
|  |  | ||||||
| // Init does nothing as the Basic implementation does not need to allocate any resources |  | ||||||
| func (b *Group) Init(ctx context.Context) error { |  | ||||||
| 	for _, method := range b.methods { |  | ||||||
| 		initializable, ok := method.(Initializable) |  | ||||||
| 		if !ok { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if err := initializable.Init(ctx); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Free does nothing as the Basic implementation does not have to release any resources |  | ||||||
| func (b *Group) Free() error { |  | ||||||
| 	for _, method := range b.methods { |  | ||||||
| 		freeable, ok := method.(Freeable) |  | ||||||
| 		if !ok { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if err := freeable.Free(); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Verify extracts and validates | // Verify extracts and validates | ||||||
| func (b *Group) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { | func (b *Group) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { | ||||||
| 	// Try to sign in with each of the enabled plugins | 	// Try to sign in with each of the enabled plugins | ||||||
|   | |||||||
| @@ -29,26 +29,11 @@ type Method interface { | |||||||
| 	Verify(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) | 	Verify(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) | ||||||
| } | } | ||||||
|  |  | ||||||
| // Initializable represents a structure that requires initialization |  | ||||||
| // It usually should only be called once before anything else is called |  | ||||||
| type Initializable interface { |  | ||||||
| 	// Init should be called exactly once before using any of the other methods, |  | ||||||
| 	// in order to allow the plugin to allocate necessary resources |  | ||||||
| 	Init(ctx context.Context) error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Named represents a named thing | // Named represents a named thing | ||||||
| type Named interface { | type Named interface { | ||||||
| 	Name() string | 	Name() string | ||||||
| } | } | ||||||
|  |  | ||||||
| // Freeable represents a structure that is required to be freed |  | ||||||
| type Freeable interface { |  | ||||||
| 	// Free should be called exactly once before application closes, in order to |  | ||||||
| 	// give chance to the plugin to free any allocated resources |  | ||||||
| 	Free() error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // PasswordAuthenticator represents a source of authentication | // PasswordAuthenticator represents a source of authentication | ||||||
| type PasswordAuthenticator interface { | type PasswordAuthenticator interface { | ||||||
| 	Authenticate(user *user_model.User, login, password string) (*user_model.User, error) | 	Authenticate(user *user_model.User, login, password string) (*user_model.User, error) | ||||||
|   | |||||||
| @@ -4,10 +4,10 @@ | |||||||
| package auth | package auth | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models/auth" | 	"code.gitea.io/gitea/models/auth" | ||||||
| 	"code.gitea.io/gitea/models/avatars" | 	"code.gitea.io/gitea/models/avatars" | ||||||
| @@ -32,13 +32,12 @@ var ( | |||||||
| 	// sspiAuth is a global instance of the websspi authentication package, | 	// sspiAuth is a global instance of the websspi authentication package, | ||||||
| 	// which is used to avoid acquiring the server credential handle on | 	// which is used to avoid acquiring the server credential handle on | ||||||
| 	// every request | 	// every request | ||||||
| 	sspiAuth *websspi.Authenticator | 	sspiAuth     *websspi.Authenticator | ||||||
|  | 	sspiAuthOnce sync.Once | ||||||
|  |  | ||||||
| 	// Ensure the struct implements the interface. | 	// Ensure the struct implements the interface. | ||||||
| 	_ Method        = &SSPI{} | 	_ Method = &SSPI{} | ||||||
| 	_ Named         = &SSPI{} | 	_ Named  = &SSPI{} | ||||||
| 	_ Initializable = &SSPI{} |  | ||||||
| 	_ Freeable      = &SSPI{} |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // SSPI implements the SingleSignOn interface and authenticates requests | // SSPI implements the SingleSignOn interface and authenticates requests | ||||||
| @@ -47,32 +46,25 @@ var ( | |||||||
| // Returns nil if authentication fails. | // Returns nil if authentication fails. | ||||||
| type SSPI struct{} | type SSPI struct{} | ||||||
|  |  | ||||||
| // Init creates a new global websspi.Authenticator object |  | ||||||
| func (s *SSPI) Init(ctx context.Context) error { |  | ||||||
| 	config := websspi.NewConfig() |  | ||||||
| 	var err error |  | ||||||
| 	sspiAuth, err = websspi.New(config) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Name represents the name of auth method | // Name represents the name of auth method | ||||||
| func (s *SSPI) Name() string { | func (s *SSPI) Name() string { | ||||||
| 	return "sspi" | 	return "sspi" | ||||||
| } | } | ||||||
|  |  | ||||||
| // Free releases resources used by the global websspi.Authenticator object |  | ||||||
| func (s *SSPI) Free() error { |  | ||||||
| 	return sspiAuth.Free() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Verify uses SSPI (Windows implementation of SPNEGO) to authenticate the request. | // Verify uses SSPI (Windows implementation of SPNEGO) to authenticate the request. | ||||||
| // If authentication is successful, returns the corresponding user object. | // If authentication is successful, returns the corresponding user object. | ||||||
| // If negotiation should continue or authentication fails, immediately returns a 401 HTTP | // If negotiation should continue or authentication fails, immediately returns a 401 HTTP | ||||||
| // response code, as required by the SPNEGO protocol. | // response code, as required by the SPNEGO protocol. | ||||||
| func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { | func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { | ||||||
|  | 	var errInit error | ||||||
|  | 	sspiAuthOnce.Do(func() { | ||||||
|  | 		config := websspi.NewConfig() | ||||||
|  | 		sspiAuth, errInit = websspi.New(config) | ||||||
|  | 	}) | ||||||
|  | 	if errInit != nil { | ||||||
|  | 		return nil, errInit | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if !s.shouldAuthenticate(req) { | 	if !s.shouldAuthenticate(req) { | ||||||
| 		return nil, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ func TestMain(m *testing.M) { | |||||||
| func TestArchive_Basic(t *testing.T) { | func TestArchive_Basic(t *testing.T) { | ||||||
| 	assert.NoError(t, unittest.PrepareTestDatabase()) | 	assert.NoError(t, unittest.PrepareTestDatabase()) | ||||||
|  |  | ||||||
| 	ctx := test.MockContext(t, "user27/repo49") | 	ctx, _ := test.MockContext(t, "user27/repo49") | ||||||
| 	firstCommit, secondCommit := "51f84af23134", "aacbdfe9e1c4" | 	firstCommit, secondCommit := "51f84af23134", "aacbdfe9e1c4" | ||||||
|  |  | ||||||
| 	test.LoadRepo(t, ctx, 49) | 	test.LoadRepo(t, ctx, 49) | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse { | |||||||
|  |  | ||||||
| func TestGetContents(t *testing.T) { | func TestGetContents(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -82,7 +82,7 @@ func TestGetContents(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetContentsOrListForDir(t *testing.T) { | func TestGetContentsOrListForDir(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -117,7 +117,7 @@ func TestGetContentsOrListForDir(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetContentsOrListForFile(t *testing.T) { | func TestGetContentsOrListForFile(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -145,7 +145,7 @@ func TestGetContentsOrListForFile(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetContentsErrors(t *testing.T) { | func TestGetContentsErrors(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -176,7 +176,7 @@ func TestGetContentsErrors(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetContentsOrListErrors(t *testing.T) { | func TestGetContentsOrListErrors(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -207,7 +207,7 @@ func TestGetContentsOrListErrors(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetContentsOrListOfEmptyRepos(t *testing.T) { | func TestGetContentsOrListOfEmptyRepos(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user30/empty") | 	ctx, _ := test.MockContext(t, "user30/empty") | ||||||
| 	ctx.SetParams(":id", "52") | 	ctx.SetParams(":id", "52") | ||||||
| 	test.LoadRepo(t, ctx, 52) | 	test.LoadRepo(t, ctx, 52) | ||||||
| 	test.LoadUser(t, ctx, 30) | 	test.LoadUser(t, ctx, 30) | ||||||
| @@ -225,7 +225,7 @@ func TestGetContentsOrListOfEmptyRepos(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetBlobBySHA(t *testing.T) { | func TestGetBlobBySHA(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ import ( | |||||||
|  |  | ||||||
| func TestGetDiffPreview(t *testing.T) { | func TestGetDiffPreview(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -139,7 +139,7 @@ func TestGetDiffPreview(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGetDiffPreviewErrors(t *testing.T) { | func TestGetDiffPreviewErrors(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
|   | |||||||
| @@ -98,7 +98,7 @@ func getExpectedFileResponse() *api.FileResponse { | |||||||
|  |  | ||||||
| func TestGetFileResponseFromCommit(t *testing.T) { | func TestGetFileResponseFromCommit(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ import ( | |||||||
|  |  | ||||||
| func TestGetTreeBySHA(t *testing.T) { | func TestGetTreeBySHA(t *testing.T) { | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| 	test.LoadUser(t, ctx, 2) | 	test.LoadUser(t, ctx, 2) | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { | |||||||
| 	defer cancel() | 	defer cancel() | ||||||
|  |  | ||||||
| 	tests.InitTest(false) | 	tests.InitTest(false) | ||||||
| 	c = routers.NormalRoutes(context.TODO()) | 	c = routers.NormalRoutes() | ||||||
|  |  | ||||||
| 	os.Unsetenv("GIT_AUTHOR_NAME") | 	os.Unsetenv("GIT_AUTHOR_NAME") | ||||||
| 	os.Unsetenv("GIT_AUTHOR_EMAIL") | 	os.Unsetenv("GIT_AUTHOR_EMAIL") | ||||||
|   | |||||||
| @@ -22,10 +22,10 @@ import ( | |||||||
|  |  | ||||||
| func TestActivityPubPerson(t *testing.T) { | func TestActivityPubPerson(t *testing.T) { | ||||||
| 	setting.Federation.Enabled = true | 	setting.Federation.Enabled = true | ||||||
| 	c = routers.NormalRoutes(context.TODO()) | 	c = routers.NormalRoutes() | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		setting.Federation.Enabled = false | 		setting.Federation.Enabled = false | ||||||
| 		c = routers.NormalRoutes(context.TODO()) | 		c = routers.NormalRoutes() | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	onGiteaRun(t, func(*testing.T, *url.URL) { | 	onGiteaRun(t, func(*testing.T, *url.URL) { | ||||||
| @@ -60,10 +60,10 @@ func TestActivityPubPerson(t *testing.T) { | |||||||
|  |  | ||||||
| func TestActivityPubMissingPerson(t *testing.T) { | func TestActivityPubMissingPerson(t *testing.T) { | ||||||
| 	setting.Federation.Enabled = true | 	setting.Federation.Enabled = true | ||||||
| 	c = routers.NormalRoutes(context.TODO()) | 	c = routers.NormalRoutes() | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		setting.Federation.Enabled = false | 		setting.Federation.Enabled = false | ||||||
| 		c = routers.NormalRoutes(context.TODO()) | 		c = routers.NormalRoutes() | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	onGiteaRun(t, func(*testing.T, *url.URL) { | 	onGiteaRun(t, func(*testing.T, *url.URL) { | ||||||
| @@ -75,10 +75,10 @@ func TestActivityPubMissingPerson(t *testing.T) { | |||||||
|  |  | ||||||
| func TestActivityPubPersonInbox(t *testing.T) { | func TestActivityPubPersonInbox(t *testing.T) { | ||||||
| 	setting.Federation.Enabled = true | 	setting.Federation.Enabled = true | ||||||
| 	c = routers.NormalRoutes(context.TODO()) | 	c = routers.NormalRoutes() | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		setting.Federation.Enabled = false | 		setting.Federation.Enabled = false | ||||||
| 		c = routers.NormalRoutes(context.TODO()) | 		c = routers.NormalRoutes() | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	srv := httptest.NewServer(c) | 	srv := httptest.NewServer(c) | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ | |||||||
| package integration | package integration | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"testing" | 	"testing" | ||||||
| @@ -18,10 +17,10 @@ import ( | |||||||
|  |  | ||||||
| func TestNodeinfo(t *testing.T) { | func TestNodeinfo(t *testing.T) { | ||||||
| 	setting.Federation.Enabled = true | 	setting.Federation.Enabled = true | ||||||
| 	c = routers.NormalRoutes(context.TODO()) | 	c = routers.NormalRoutes() | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		setting.Federation.Enabled = false | 		setting.Federation.Enabled = false | ||||||
| 		c = routers.NormalRoutes(context.TODO()) | 		c = routers.NormalRoutes() | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	onGiteaRun(t, func(*testing.T, *url.URL) { | 	onGiteaRun(t, func(*testing.T, *url.URL) { | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ | |||||||
| package integration | package integration | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
| 	"os" | 	"os" | ||||||
| @@ -57,7 +56,7 @@ func TestSessionFileCreation(t *testing.T) { | |||||||
| 	oldSessionConfig := setting.SessionConfig.ProviderConfig | 	oldSessionConfig := setting.SessionConfig.ProviderConfig | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		setting.SessionConfig.ProviderConfig = oldSessionConfig | 		setting.SessionConfig.ProviderConfig = oldSessionConfig | ||||||
| 		c = routers.NormalRoutes(context.TODO()) | 		c = routers.NormalRoutes() | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	var config session.Options | 	var config session.Options | ||||||
| @@ -76,7 +75,7 @@ func TestSessionFileCreation(t *testing.T) { | |||||||
|  |  | ||||||
| 	setting.SessionConfig.ProviderConfig = string(newConfigBytes) | 	setting.SessionConfig.ProviderConfig = string(newConfigBytes) | ||||||
|  |  | ||||||
| 	c = routers.NormalRoutes(context.TODO()) | 	c = routers.NormalRoutes() | ||||||
|  |  | ||||||
| 	t.Run("NoSessionOnViewIssue", func(t *testing.T) { | 	t.Run("NoSessionOnViewIssue", func(t *testing.T) { | ||||||
| 		defer tests.PrintCurrentTest(t)() | 		defer tests.PrintCurrentTest(t)() | ||||||
|   | |||||||
| @@ -87,7 +87,7 @@ func TestMain(m *testing.M) { | |||||||
| 	defer cancel() | 	defer cancel() | ||||||
|  |  | ||||||
| 	tests.InitTest(true) | 	tests.InitTest(true) | ||||||
| 	c = routers.NormalRoutes(context.TODO()) | 	c = routers.NormalRoutes() | ||||||
|  |  | ||||||
| 	// integration test settings... | 	// integration test settings... | ||||||
| 	if setting.CfgProvider != nil { | 	if setting.CfgProvider != nil { | ||||||
|   | |||||||
| @@ -244,7 +244,7 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA | |||||||
| func TestChangeRepoFilesForCreate(t *testing.T) { | func TestChangeRepoFilesForCreate(t *testing.T) { | ||||||
| 	// setup | 	// setup | ||||||
| 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | ||||||
| 		ctx := test.MockContext(t, "user2/repo1") | 		ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 		ctx.SetParams(":id", "1") | 		ctx.SetParams(":id", "1") | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| 		test.LoadRepoCommit(t, ctx) | 		test.LoadRepoCommit(t, ctx) | ||||||
| @@ -281,7 +281,7 @@ func TestChangeRepoFilesForCreate(t *testing.T) { | |||||||
| func TestChangeRepoFilesForUpdate(t *testing.T) { | func TestChangeRepoFilesForUpdate(t *testing.T) { | ||||||
| 	// setup | 	// setup | ||||||
| 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | ||||||
| 		ctx := test.MockContext(t, "user2/repo1") | 		ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 		ctx.SetParams(":id", "1") | 		ctx.SetParams(":id", "1") | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| 		test.LoadRepoCommit(t, ctx) | 		test.LoadRepoCommit(t, ctx) | ||||||
| @@ -315,7 +315,7 @@ func TestChangeRepoFilesForUpdate(t *testing.T) { | |||||||
| func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { | func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { | ||||||
| 	// setup | 	// setup | ||||||
| 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | ||||||
| 		ctx := test.MockContext(t, "user2/repo1") | 		ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 		ctx.SetParams(":id", "1") | 		ctx.SetParams(":id", "1") | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| 		test.LoadRepoCommit(t, ctx) | 		test.LoadRepoCommit(t, ctx) | ||||||
| @@ -366,7 +366,7 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { | |||||||
| func TestChangeRepoFilesWithoutBranchNames(t *testing.T) { | func TestChangeRepoFilesWithoutBranchNames(t *testing.T) { | ||||||
| 	// setup | 	// setup | ||||||
| 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | ||||||
| 		ctx := test.MockContext(t, "user2/repo1") | 		ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 		ctx.SetParams(":id", "1") | 		ctx.SetParams(":id", "1") | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| 		test.LoadRepoCommit(t, ctx) | 		test.LoadRepoCommit(t, ctx) | ||||||
| @@ -402,7 +402,7 @@ func TestChangeRepoFilesForDelete(t *testing.T) { | |||||||
| func testDeleteRepoFiles(t *testing.T, u *url.URL) { | func testDeleteRepoFiles(t *testing.T, u *url.URL) { | ||||||
| 	// setup | 	// setup | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -441,7 +441,7 @@ func TestChangeRepoFilesForDeleteWithoutBranchNames(t *testing.T) { | |||||||
| func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { | func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { | ||||||
| 	// setup | 	// setup | ||||||
| 	unittest.PrepareTestEnv(t) | 	unittest.PrepareTestEnv(t) | ||||||
| 	ctx := test.MockContext(t, "user2/repo1") | 	ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 	ctx.SetParams(":id", "1") | 	ctx.SetParams(":id", "1") | ||||||
| 	test.LoadRepo(t, ctx, 1) | 	test.LoadRepo(t, ctx, 1) | ||||||
| 	test.LoadRepoCommit(t, ctx) | 	test.LoadRepoCommit(t, ctx) | ||||||
| @@ -471,7 +471,7 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { | |||||||
| func TestChangeRepoFilesErrors(t *testing.T) { | func TestChangeRepoFilesErrors(t *testing.T) { | ||||||
| 	// setup | 	// setup | ||||||
| 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | ||||||
| 		ctx := test.MockContext(t, "user2/repo1") | 		ctx, _ := test.MockContext(t, "user2/repo1") | ||||||
| 		ctx.SetParams(":id", "1") | 		ctx.SetParams(":id", "1") | ||||||
| 		test.LoadRepo(t, ctx, 1) | 		test.LoadRepo(t, ctx, 1) | ||||||
| 		test.LoadRepoCommit(t, ctx) | 		test.LoadRepoCommit(t, ctx) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 wxiaoguang
					wxiaoguang