Skip to content

Commit fa8f2a4

Browse files
authored
Merge branch 'main' into show-assignees-right
2 parents 68841c4 + a92f505 commit fa8f2a4

36 files changed

+635
-971
lines changed

.eslintrc.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ module.exports = {
674674
'no-this-before-super': [2],
675675
'no-throw-literal': [2],
676676
'no-undef-init': [2],
677-
'no-undef': [0],
677+
'no-undef': [2], // it is still needed by eslint & IDE to prompt undefined names in real time
678678
'no-undefined': [0],
679679
'no-underscore-dangle': [0],
680680
'no-unexpected-multiline': [2],

models/activities/repo_activity.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"code.gitea.io/gitea/modules/git"
1717
"code.gitea.io/gitea/modules/gitrepo"
1818

19+
"xorm.io/builder"
1920
"xorm.io/xorm"
2021
)
2122

@@ -337,8 +338,10 @@ func newlyCreatedIssues(ctx context.Context, repoID int64, fromTime time.Time) *
337338
func activeIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
338339
sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
339340
And("issue.is_pull = ?", false).
340-
And("issue.created_unix >= ?", fromTime.Unix()).
341-
Or("issue.closed_unix >= ?", fromTime.Unix())
341+
And(builder.Or(
342+
builder.Gte{"issue.created_unix": fromTime.Unix()},
343+
builder.Gte{"issue.closed_unix": fromTime.Unix()},
344+
))
342345

343346
return sess
344347
}

modules/web/route.go renamed to modules/web/router.go

Lines changed: 19 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,14 @@
44
package web
55

66
import (
7-
"fmt"
87
"net/http"
98
"net/url"
109
"reflect"
11-
"regexp"
1210
"strings"
1311

14-
"code.gitea.io/gitea/modules/container"
1512
"code.gitea.io/gitea/modules/htmlutil"
1613
"code.gitea.io/gitea/modules/reqctx"
1714
"code.gitea.io/gitea/modules/setting"
18-
"code.gitea.io/gitea/modules/util"
1915
"code.gitea.io/gitea/modules/web/middleware"
2016

2117
"gitea.com/go-chi/binding"
@@ -45,7 +41,7 @@ func GetForm(dataStore reqctx.RequestDataStore) any {
4541

4642
// Router defines a route based on chi's router
4743
type Router struct {
48-
chiRouter chi.Router
44+
chiRouter *chi.Mux
4945
curGroupPrefix string
5046
curMiddlewares []any
5147
}
@@ -97,16 +93,21 @@ func isNilOrFuncNil(v any) bool {
9793
return r.Kind() == reflect.Func && r.IsNil()
9894
}
9995

100-
func (r *Router) wrapMiddlewareAndHandler(h []any) ([]func(http.Handler) http.Handler, http.HandlerFunc) {
101-
handlerProviders := make([]func(http.Handler) http.Handler, 0, len(r.curMiddlewares)+len(h)+1)
102-
for _, m := range r.curMiddlewares {
96+
func wrapMiddlewareAndHandler(curMiddlewares, h []any) ([]func(http.Handler) http.Handler, http.HandlerFunc) {
97+
handlerProviders := make([]func(http.Handler) http.Handler, 0, len(curMiddlewares)+len(h)+1)
98+
for _, m := range curMiddlewares {
10399
if !isNilOrFuncNil(m) {
104100
handlerProviders = append(handlerProviders, toHandlerProvider(m))
105101
}
106102
}
107-
for _, m := range h {
103+
if len(h) == 0 {
104+
panic("no endpoint handler provided")
105+
}
106+
for i, m := range h {
108107
if !isNilOrFuncNil(m) {
109108
handlerProviders = append(handlerProviders, toHandlerProvider(m))
109+
} else if i == len(h)-1 {
110+
panic("endpoint handler can't be nil")
110111
}
111112
}
112113
middlewares := handlerProviders[:len(handlerProviders)-1]
@@ -121,7 +122,7 @@ func (r *Router) wrapMiddlewareAndHandler(h []any) ([]func(http.Handler) http.Ha
121122
// Methods adds the same handlers for multiple http "methods" (separated by ",").
122123
// If any method is invalid, the lower level router will panic.
123124
func (r *Router) Methods(methods, pattern string, h ...any) {
124-
middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h)
125+
middlewares, handlerFunc := wrapMiddlewareAndHandler(r.curMiddlewares, h)
125126
fullPattern := r.getPattern(pattern)
126127
if strings.Contains(methods, ",") {
127128
methods := strings.Split(methods, ",")
@@ -141,7 +142,7 @@ func (r *Router) Mount(pattern string, subRouter *Router) {
141142

142143
// Any delegate requests for all methods
143144
func (r *Router) Any(pattern string, h ...any) {
144-
middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h)
145+
middlewares, handlerFunc := wrapMiddlewareAndHandler(r.curMiddlewares, h)
145146
r.chiRouter.With(middlewares...).HandleFunc(r.getPattern(pattern), handlerFunc)
146147
}
147148

@@ -185,17 +186,6 @@ func (r *Router) NotFound(h http.HandlerFunc) {
185186
r.chiRouter.NotFound(h)
186187
}
187188

188-
type pathProcessorParam struct {
189-
name string
190-
captureGroup int
191-
}
192-
193-
type PathProcessor struct {
194-
methods container.Set[string]
195-
re *regexp.Regexp
196-
params []pathProcessorParam
197-
}
198-
199189
func (r *Router) normalizeRequestPath(resp http.ResponseWriter, req *http.Request, next http.Handler) {
200190
normalized := false
201191
normalizedPath := req.URL.EscapedPath()
@@ -253,121 +243,16 @@ func (r *Router) normalizeRequestPath(resp http.ResponseWriter, req *http.Reques
253243
next.ServeHTTP(resp, req)
254244
}
255245

256-
func (p *PathProcessor) ProcessRequestPath(chiCtx *chi.Context, path string) bool {
257-
if !p.methods.Contains(chiCtx.RouteMethod) {
258-
return false
259-
}
260-
if !strings.HasPrefix(path, "/") {
261-
path = "/" + path
262-
}
263-
pathMatches := p.re.FindStringSubmatchIndex(path) // Golang regexp match pairs [start, end, start, end, ...]
264-
if pathMatches == nil {
265-
return false
266-
}
267-
var paramMatches [][]int
268-
for i := 2; i < len(pathMatches); {
269-
paramMatches = append(paramMatches, []int{pathMatches[i], pathMatches[i+1]})
270-
pmIdx := len(paramMatches) - 1
271-
end := pathMatches[i+1]
272-
i += 2
273-
for ; i < len(pathMatches); i += 2 {
274-
if pathMatches[i] >= end {
275-
break
276-
}
277-
paramMatches[pmIdx] = append(paramMatches[pmIdx], pathMatches[i], pathMatches[i+1])
278-
}
279-
}
280-
for i, pm := range paramMatches {
281-
groupIdx := p.params[i].captureGroup * 2
282-
chiCtx.URLParams.Add(p.params[i].name, path[pm[groupIdx]:pm[groupIdx+1]])
283-
}
284-
return true
285-
}
286-
287-
func NewPathProcessor(methods, pattern string) *PathProcessor {
288-
p := &PathProcessor{methods: make(container.Set[string])}
289-
for _, method := range strings.Split(methods, ",") {
290-
p.methods.Add(strings.TrimSpace(method))
291-
}
292-
re := []byte{'^'}
293-
lastEnd := 0
294-
for lastEnd < len(pattern) {
295-
start := strings.IndexByte(pattern[lastEnd:], '<')
296-
if start == -1 {
297-
re = append(re, pattern[lastEnd:]...)
298-
break
299-
}
300-
end := strings.IndexByte(pattern[lastEnd+start:], '>')
301-
if end == -1 {
302-
panic(fmt.Sprintf("invalid pattern: %s", pattern))
303-
}
304-
re = append(re, pattern[lastEnd:lastEnd+start]...)
305-
partName, partExp, _ := strings.Cut(pattern[lastEnd+start+1:lastEnd+start+end], ":")
306-
lastEnd += start + end + 1
307-
308-
// TODO: it could support to specify a "capture group" for the name, for example: "/<name[2]:(\d)-(\d)>"
309-
// it is not used so no need to implement it now
310-
param := pathProcessorParam{}
311-
if partExp == "*" {
312-
re = append(re, "(.*?)/?"...)
313-
if lastEnd < len(pattern) {
314-
if pattern[lastEnd] == '/' {
315-
lastEnd++
316-
}
317-
}
318-
} else {
319-
partExp = util.IfZero(partExp, "[^/]+")
320-
re = append(re, '(')
321-
re = append(re, partExp...)
322-
re = append(re, ')')
323-
}
324-
param.name = partName
325-
p.params = append(p.params, param)
326-
}
327-
re = append(re, '$')
328-
reStr := string(re)
329-
p.re = regexp.MustCompile(reStr)
330-
return p
331-
}
332-
333246
// Combo delegates requests to Combo
334247
func (r *Router) Combo(pattern string, h ...any) *Combo {
335248
return &Combo{r, pattern, h}
336249
}
337250

338-
// Combo represents a tiny group routes with same pattern
339-
type Combo struct {
340-
r *Router
341-
pattern string
342-
h []any
343-
}
344-
345-
// Get delegates Get method
346-
func (c *Combo) Get(h ...any) *Combo {
347-
c.r.Get(c.pattern, append(c.h, h...)...)
348-
return c
349-
}
350-
351-
// Post delegates Post method
352-
func (c *Combo) Post(h ...any) *Combo {
353-
c.r.Post(c.pattern, append(c.h, h...)...)
354-
return c
355-
}
356-
357-
// Delete delegates Delete method
358-
func (c *Combo) Delete(h ...any) *Combo {
359-
c.r.Delete(c.pattern, append(c.h, h...)...)
360-
return c
361-
}
362-
363-
// Put delegates Put method
364-
func (c *Combo) Put(h ...any) *Combo {
365-
c.r.Put(c.pattern, append(c.h, h...)...)
366-
return c
367-
}
368-
369-
// Patch delegates Patch method
370-
func (c *Combo) Patch(h ...any) *Combo {
371-
c.r.Patch(c.pattern, append(c.h, h...)...)
372-
return c
251+
// PathGroup creates a group of paths which could be matched by regexp.
252+
// It is only designed to resolve some special cases which chi router can't handle.
253+
// For most cases, it shouldn't be used because it needs to iterate all rules to find the matched one (inefficient).
254+
func (r *Router) PathGroup(pattern string, fn func(g *RouterPathGroup), h ...any) {
255+
g := &RouterPathGroup{r: r, pathParam: "*"}
256+
fn(g)
257+
r.Any(pattern, append(h, g.ServeHTTP)...)
373258
}

modules/web/router_combo.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package web
5+
6+
// Combo represents a tiny group routes with same pattern
7+
type Combo struct {
8+
r *Router
9+
pattern string
10+
h []any
11+
}
12+
13+
// Get delegates Get method
14+
func (c *Combo) Get(h ...any) *Combo {
15+
c.r.Get(c.pattern, append(c.h, h...)...)
16+
return c
17+
}
18+
19+
// Post delegates Post method
20+
func (c *Combo) Post(h ...any) *Combo {
21+
c.r.Post(c.pattern, append(c.h, h...)...)
22+
return c
23+
}
24+
25+
// Delete delegates Delete method
26+
func (c *Combo) Delete(h ...any) *Combo {
27+
c.r.Delete(c.pattern, append(c.h, h...)...)
28+
return c
29+
}
30+
31+
// Put delegates Put method
32+
func (c *Combo) Put(h ...any) *Combo {
33+
c.r.Put(c.pattern, append(c.h, h...)...)
34+
return c
35+
}
36+
37+
// Patch delegates Patch method
38+
func (c *Combo) Patch(h ...any) *Combo {
39+
c.r.Patch(c.pattern, append(c.h, h...)...)
40+
return c
41+
}

0 commit comments

Comments
 (0)