code.gitea.io/gitea@v1.19.3/modules/web/route.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package web
     5  
     6  import (
     7  	goctx "context"
     8  	"fmt"
     9  	"net/http"
    10  	"strings"
    11  
    12  	"code.gitea.io/gitea/modules/context"
    13  	"code.gitea.io/gitea/modules/web/middleware"
    14  
    15  	"gitea.com/go-chi/binding"
    16  	chi "github.com/go-chi/chi/v5"
    17  )
    18  
    19  // Bind binding an obj to a handler
    20  func Bind[T any](obj T) http.HandlerFunc {
    21  	return Wrap(func(ctx *context.Context) {
    22  		theObj := new(T) // create a new form obj for every request but not use obj directly
    23  		binding.Bind(ctx.Req, theObj)
    24  		SetForm(ctx, theObj)
    25  		middleware.AssignForm(theObj, ctx.Data)
    26  	})
    27  }
    28  
    29  // SetForm set the form object
    30  func SetForm(data middleware.DataStore, obj interface{}) {
    31  	data.GetData()["__form"] = obj
    32  }
    33  
    34  // GetForm returns the validate form information
    35  func GetForm(data middleware.DataStore) interface{} {
    36  	return data.GetData()["__form"]
    37  }
    38  
    39  // Route defines a route based on chi's router
    40  type Route struct {
    41  	R              chi.Router
    42  	curGroupPrefix string
    43  	curMiddlewares []interface{}
    44  }
    45  
    46  // NewRoute creates a new route
    47  func NewRoute() *Route {
    48  	r := chi.NewRouter()
    49  	return &Route{
    50  		R:              r,
    51  		curGroupPrefix: "",
    52  		curMiddlewares: []interface{}{},
    53  	}
    54  }
    55  
    56  // Use supports two middlewares
    57  func (r *Route) Use(middlewares ...interface{}) {
    58  	if r.curGroupPrefix != "" {
    59  		r.curMiddlewares = append(r.curMiddlewares, middlewares...)
    60  	} else {
    61  		for _, middle := range middlewares {
    62  			switch t := middle.(type) {
    63  			case func(http.Handler) http.Handler:
    64  				r.R.Use(t)
    65  			case func(*context.Context):
    66  				r.R.Use(Middle(t))
    67  			case func(*context.Context) goctx.CancelFunc:
    68  				r.R.Use(MiddleCancel(t))
    69  			case func(*context.APIContext):
    70  				r.R.Use(MiddleAPI(t))
    71  			default:
    72  				panic(fmt.Sprintf("Unsupported middleware type: %#v", t))
    73  			}
    74  		}
    75  	}
    76  }
    77  
    78  // Group mounts a sub-Router along a `pattern` string.
    79  func (r *Route) Group(pattern string, fn func(), middlewares ...interface{}) {
    80  	previousGroupPrefix := r.curGroupPrefix
    81  	previousMiddlewares := r.curMiddlewares
    82  	r.curGroupPrefix += pattern
    83  	r.curMiddlewares = append(r.curMiddlewares, middlewares...)
    84  
    85  	fn()
    86  
    87  	r.curGroupPrefix = previousGroupPrefix
    88  	r.curMiddlewares = previousMiddlewares
    89  }
    90  
    91  func (r *Route) getPattern(pattern string) string {
    92  	newPattern := r.curGroupPrefix + pattern
    93  	if !strings.HasPrefix(newPattern, "/") {
    94  		newPattern = "/" + newPattern
    95  	}
    96  	if newPattern == "/" {
    97  		return newPattern
    98  	}
    99  	return strings.TrimSuffix(newPattern, "/")
   100  }
   101  
   102  // Mount attaches another Route along ./pattern/*
   103  func (r *Route) Mount(pattern string, subR *Route) {
   104  	middlewares := make([]interface{}, len(r.curMiddlewares))
   105  	copy(middlewares, r.curMiddlewares)
   106  	subR.Use(middlewares...)
   107  	r.R.Mount(r.getPattern(pattern), subR.R)
   108  }
   109  
   110  // Any delegate requests for all methods
   111  func (r *Route) Any(pattern string, h ...interface{}) {
   112  	middlewares := r.getMiddlewares(h)
   113  	r.R.HandleFunc(r.getPattern(pattern), Wrap(middlewares...))
   114  }
   115  
   116  // Route delegate special methods
   117  func (r *Route) Route(pattern, methods string, h ...interface{}) {
   118  	p := r.getPattern(pattern)
   119  	ms := strings.Split(methods, ",")
   120  	middlewares := r.getMiddlewares(h)
   121  	for _, method := range ms {
   122  		r.R.MethodFunc(strings.TrimSpace(method), p, Wrap(middlewares...))
   123  	}
   124  }
   125  
   126  // Delete delegate delete method
   127  func (r *Route) Delete(pattern string, h ...interface{}) {
   128  	middlewares := r.getMiddlewares(h)
   129  	r.R.Delete(r.getPattern(pattern), Wrap(middlewares...))
   130  }
   131  
   132  func (r *Route) getMiddlewares(h []interface{}) []interface{} {
   133  	middlewares := make([]interface{}, len(r.curMiddlewares), len(r.curMiddlewares)+len(h))
   134  	copy(middlewares, r.curMiddlewares)
   135  	middlewares = append(middlewares, h...)
   136  	return middlewares
   137  }
   138  
   139  // Get delegate get method
   140  func (r *Route) Get(pattern string, h ...interface{}) {
   141  	middlewares := r.getMiddlewares(h)
   142  	r.R.Get(r.getPattern(pattern), Wrap(middlewares...))
   143  }
   144  
   145  // Options delegate options method
   146  func (r *Route) Options(pattern string, h ...interface{}) {
   147  	middlewares := r.getMiddlewares(h)
   148  	r.R.Options(r.getPattern(pattern), Wrap(middlewares...))
   149  }
   150  
   151  // GetOptions delegate get and options method
   152  func (r *Route) GetOptions(pattern string, h ...interface{}) {
   153  	middlewares := r.getMiddlewares(h)
   154  	r.R.Get(r.getPattern(pattern), Wrap(middlewares...))
   155  	r.R.Options(r.getPattern(pattern), Wrap(middlewares...))
   156  }
   157  
   158  // PostOptions delegate post and options method
   159  func (r *Route) PostOptions(pattern string, h ...interface{}) {
   160  	middlewares := r.getMiddlewares(h)
   161  	r.R.Post(r.getPattern(pattern), Wrap(middlewares...))
   162  	r.R.Options(r.getPattern(pattern), Wrap(middlewares...))
   163  }
   164  
   165  // Head delegate head method
   166  func (r *Route) Head(pattern string, h ...interface{}) {
   167  	middlewares := r.getMiddlewares(h)
   168  	r.R.Head(r.getPattern(pattern), Wrap(middlewares...))
   169  }
   170  
   171  // Post delegate post method
   172  func (r *Route) Post(pattern string, h ...interface{}) {
   173  	middlewares := r.getMiddlewares(h)
   174  	r.R.Post(r.getPattern(pattern), Wrap(middlewares...))
   175  }
   176  
   177  // Put delegate put method
   178  func (r *Route) Put(pattern string, h ...interface{}) {
   179  	middlewares := r.getMiddlewares(h)
   180  	r.R.Put(r.getPattern(pattern), Wrap(middlewares...))
   181  }
   182  
   183  // Patch delegate patch method
   184  func (r *Route) Patch(pattern string, h ...interface{}) {
   185  	middlewares := r.getMiddlewares(h)
   186  	r.R.Patch(r.getPattern(pattern), Wrap(middlewares...))
   187  }
   188  
   189  // ServeHTTP implements http.Handler
   190  func (r *Route) ServeHTTP(w http.ResponseWriter, req *http.Request) {
   191  	r.R.ServeHTTP(w, req)
   192  }
   193  
   194  // NotFound defines a handler to respond whenever a route could
   195  // not be found.
   196  func (r *Route) NotFound(h http.HandlerFunc) {
   197  	r.R.NotFound(h)
   198  }
   199  
   200  // MethodNotAllowed defines a handler to respond whenever a method is
   201  // not allowed.
   202  func (r *Route) MethodNotAllowed(h http.HandlerFunc) {
   203  	r.R.MethodNotAllowed(h)
   204  }
   205  
   206  // Combo deletegate requests to Combo
   207  func (r *Route) Combo(pattern string, h ...interface{}) *Combo {
   208  	return &Combo{r, pattern, h}
   209  }
   210  
   211  // Combo represents a tiny group routes with same pattern
   212  type Combo struct {
   213  	r       *Route
   214  	pattern string
   215  	h       []interface{}
   216  }
   217  
   218  // Get deletegate Get method
   219  func (c *Combo) Get(h ...interface{}) *Combo {
   220  	c.r.Get(c.pattern, append(c.h, h...)...)
   221  	return c
   222  }
   223  
   224  // Post deletegate Post method
   225  func (c *Combo) Post(h ...interface{}) *Combo {
   226  	c.r.Post(c.pattern, append(c.h, h...)...)
   227  	return c
   228  }
   229  
   230  // Delete deletegate Delete method
   231  func (c *Combo) Delete(h ...interface{}) *Combo {
   232  	c.r.Delete(c.pattern, append(c.h, h...)...)
   233  	return c
   234  }
   235  
   236  // Put deletegate Put method
   237  func (c *Combo) Put(h ...interface{}) *Combo {
   238  	c.r.Put(c.pattern, append(c.h, h...)...)
   239  	return c
   240  }
   241  
   242  // Patch deletegate Patch method
   243  func (c *Combo) Patch(h ...interface{}) *Combo {
   244  	c.r.Patch(c.pattern, append(c.h, h...)...)
   245  	return c
   246  }