@@ -13,18 +13,31 @@ import (
13
13
14
14
"code.gitea.io/gitea/models/auth"
15
15
repo_model "code.gitea.io/gitea/models/repo"
16
- "code.gitea.io/gitea/modules/cache"
16
+ "code.gitea.io/gitea/models/unit"
17
+ user_model "code.gitea.io/gitea/models/user"
18
+ mc "code.gitea.io/gitea/modules/cache"
17
19
"code.gitea.io/gitea/modules/git"
18
20
"code.gitea.io/gitea/modules/httpcache"
19
21
"code.gitea.io/gitea/modules/log"
20
22
"code.gitea.io/gitea/modules/setting"
21
- "code.gitea.io/gitea/modules/web/middleware"
23
+
24
+ "gitea.com/go-chi/cache"
22
25
)
23
26
24
27
// APIContext is a specific context for API service
25
28
type APIContext struct {
26
- * Context
27
- Org * APIOrganization
29
+ * Base
30
+
31
+ Cache cache.Cache
32
+
33
+ Doer * user_model.User
34
+ IsSigned bool
35
+ IsBasicAuth bool
36
+
37
+ ContextUser * user_model.User
38
+ Repo * Repository
39
+ Org * APIOrganization
40
+ Package * Package
28
41
}
29
42
30
43
// Currently, we have the following common fields in error response:
@@ -128,11 +141,6 @@ type apiContextKeyType struct{}
128
141
129
142
var apiContextKey = apiContextKeyType {}
130
143
131
- // WithAPIContext set up api context in request
132
- func WithAPIContext (req * http.Request , ctx * APIContext ) * http.Request {
133
- return req .WithContext (context .WithValue (req .Context (), apiContextKey , ctx ))
134
- }
135
-
136
144
// GetAPIContext returns a context for API routes
137
145
func GetAPIContext (req * http.Request ) * APIContext {
138
146
return req .Context ().Value (apiContextKey ).(* APIContext )
@@ -195,21 +203,21 @@ func (ctx *APIContext) CheckForOTP() {
195
203
}
196
204
197
205
otpHeader := ctx .Req .Header .Get ("X-Gitea-OTP" )
198
- twofa , err := auth .GetTwoFactorByUID (ctx .Context . Doer .ID )
206
+ twofa , err := auth .GetTwoFactorByUID (ctx .Doer .ID )
199
207
if err != nil {
200
208
if auth .IsErrTwoFactorNotEnrolled (err ) {
201
209
return // No 2FA enrollment for this user
202
210
}
203
- ctx .Context . Error (http .StatusInternalServerError )
211
+ ctx .Error (http .StatusInternalServerError , "GetTwoFactorByUID" , err )
204
212
return
205
213
}
206
214
ok , err := twofa .ValidateTOTP (otpHeader )
207
215
if err != nil {
208
- ctx .Context . Error (http .StatusInternalServerError )
216
+ ctx .Error (http .StatusInternalServerError , "ValidateTOTP" , err )
209
217
return
210
218
}
211
219
if ! ok {
212
- ctx .Context . Error (http .StatusUnauthorized )
220
+ ctx .Error (http .StatusUnauthorized , "" , nil )
213
221
return
214
222
}
215
223
}
@@ -218,23 +226,17 @@ func (ctx *APIContext) CheckForOTP() {
218
226
func APIContexter () func (http.Handler ) http.Handler {
219
227
return func (next http.Handler ) http.Handler {
220
228
return http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
221
- locale := middleware .Locale (w , req )
222
- ctx := APIContext {
223
- Context : & Context {
224
- Resp : NewResponse (w ),
225
- Data : middleware .GetContextData (req .Context ()),
226
- Locale : locale ,
227
- Cache : cache .GetCache (),
228
- Repo : & Repository {
229
- PullRequest : & PullRequest {},
230
- },
231
- Org : & Organization {},
232
- },
233
- Org : & APIOrganization {},
229
+ base , baseCleanUp := NewBaseContext (w , req )
230
+ ctx := & APIContext {
231
+ Base : base ,
232
+ Cache : mc .GetCache (),
233
+ Repo : & Repository {PullRequest : & PullRequest {}},
234
+ Org : & APIOrganization {},
234
235
}
235
- defer ctx . Close ()
236
+ defer baseCleanUp ()
236
237
237
- ctx .Req = WithAPIContext (WithContext (req , ctx .Context ), & ctx )
238
+ ctx .Base .AppendContextValue (apiContextKey , ctx )
239
+ ctx .Base .AppendContextValueFunc (git .RepositoryContextKey , func () any { return ctx .Repo .GitRepo })
238
240
239
241
// If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
240
242
if ctx .Req .Method == "POST" && strings .Contains (ctx .Req .Header .Get ("Content-Type" ), "multipart/form-data" ) {
@@ -247,8 +249,6 @@ func APIContexter() func(http.Handler) http.Handler {
247
249
httpcache .SetCacheControlInHeader (ctx .Resp .Header (), 0 , "no-transform" )
248
250
ctx .Resp .Header ().Set (`X-Frame-Options` , setting .CORSConfig .XFrameOptions )
249
251
250
- ctx .Data ["Context" ] = & ctx
251
-
252
252
next .ServeHTTP (ctx .Resp , ctx .Req )
253
253
})
254
254
}
@@ -301,7 +301,7 @@ func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) (cancel context
301
301
return func () {
302
302
// If it's been set to nil then assume someone else has closed it.
303
303
if ctx .Repo .GitRepo != nil {
304
- ctx .Repo .GitRepo .Close ()
304
+ _ = ctx .Repo .GitRepo .Close ()
305
305
}
306
306
}
307
307
}
@@ -337,7 +337,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
337
337
}
338
338
339
339
var err error
340
- refName := getRefName (ctx .Context , RepoRefAny )
340
+ refName := getRefName (ctx .Base , ctx . Repo , RepoRefAny )
341
341
342
342
if ctx .Repo .GitRepo .IsBranchExist (refName ) {
343
343
ctx .Repo .Commit , err = ctx .Repo .GitRepo .GetBranchCommit (refName )
@@ -368,3 +368,44 @@ func RepoRefForAPI(next http.Handler) http.Handler {
368
368
next .ServeHTTP (w , req )
369
369
})
370
370
}
371
+
372
+ // HasAPIError returns true if error occurs in form validation.
373
+ func (ctx * APIContext ) HasAPIError () bool {
374
+ hasErr , ok := ctx .Data ["HasError" ]
375
+ if ! ok {
376
+ return false
377
+ }
378
+ return hasErr .(bool )
379
+ }
380
+
381
+ // NotFoundOrServerError use error check function to determine if the error
382
+ // is about not found. It responds with 404 status code for not found error,
383
+ // or error context description for logging purpose of 500 server error.
384
+ func (ctx * APIContext ) NotFoundOrServerError (logMsg string , errCheck func (error ) bool , logErr error ) {
385
+ if errCheck (logErr ) {
386
+ ctx .JSON (http .StatusNotFound , nil )
387
+ return
388
+ }
389
+ ctx .Error (http .StatusInternalServerError , "NotFoundOrServerError" , logMsg )
390
+ }
391
+
392
+ // IsUserSiteAdmin returns true if current user is a site admin
393
+ func (ctx * APIContext ) IsUserSiteAdmin () bool {
394
+ return ctx .IsSigned && ctx .Doer .IsAdmin
395
+ }
396
+
397
+ // IsUserRepoAdmin returns true if current user is admin in current repo
398
+ func (ctx * APIContext ) IsUserRepoAdmin () bool {
399
+ return ctx .Repo .IsAdmin ()
400
+ }
401
+
402
+ // IsUserRepoWriter returns true if current user has write privilege in current repo
403
+ func (ctx * APIContext ) IsUserRepoWriter (unitTypes []unit.Type ) bool {
404
+ for _ , unitType := range unitTypes {
405
+ if ctx .Repo .CanWrite (unitType ) {
406
+ return true
407
+ }
408
+ }
409
+
410
+ return false
411
+ }
0 commit comments