diff --git a/_examples/view/layout/blocks/main.go b/_examples/view/layout/blocks/main.go index 62b86b4c..f65155fb 100644 --- a/_examples/view/layout/blocks/main.go +++ b/_examples/view/layout/blocks/main.go @@ -8,6 +8,7 @@ func main() { // Note, in Blocks engine, layouts // are used by their base names, the // blocks.LayoutDir(layoutDir) defaults to "./layouts". + // .Blocks(...).Layout("main") for default layout for all views, it can be modified through ctx.ViewLayout though. app.Get("/", index) diff --git a/_examples/view/template_blocks_0/views/500.html b/_examples/view/template_blocks_0/views/500.html index 37c58b58..bbdd7463 100644 --- a/_examples/view/template_blocks_0/views/500.html +++ b/_examples/view/template_blocks_0/views/500.html @@ -1,8 +1,3 @@ - {{ define "content" }}

Internal Server Error

{{ end }} diff --git a/_examples/view/template_blocks_0/views/layouts/error.html b/_examples/view/template_blocks_0/views/layouts/error.html index 48598789..c61972f0 100644 --- a/_examples/view/template_blocks_0/views/layouts/error.html +++ b/_examples/view/template_blocks_0/views/layouts/error.html @@ -6,8 +6,8 @@ {{.Code}} - {{ template "content" .}} + {{ template "content" . }} - {{block "message" .}}{{end}} + {{ block "message" . }}Default Error Message{{ end }} \ No newline at end of file diff --git a/_examples/view/template_blocks_2/main.go b/_examples/view/template_blocks_2/main.go new file mode 100644 index 00000000..d494961f --- /dev/null +++ b/_examples/view/template_blocks_2/main.go @@ -0,0 +1,38 @@ +package main + +import "github.com/kataras/iris/v12" + +// Based on https://github.com/kataras/iris/issues/2214. +func main() { + app := initApp() + app.Listen(":8080") +} + +func initApp() *iris.Application { + app := iris.New() + app.Logger().SetLevel("debug") + + tmpl := iris.Blocks("./src/public/html", ".html") + tmpl.Layout("main") + app.RegisterView(tmpl) + + app.Get("/list", func(ctx iris.Context) { + ctx.View("files/list") + }) + + app.Get("/menu", func(ctx iris.Context) { + ctx.View("menu/menu") + }) + + app.Get("/list2", func(ctx iris.Context) { + ctx.ViewLayout("secondary") + ctx.View("files/list") + }) + + app.Get("/menu2", func(ctx iris.Context) { + ctx.ViewLayout("secondary") + ctx.View("menu/menu") + }) + + return app +} diff --git a/_examples/view/template_blocks_2/src/public/html/files/list.html b/_examples/view/template_blocks_2/src/public/html/files/list.html new file mode 100644 index 00000000..b2bf68b9 --- /dev/null +++ b/_examples/view/template_blocks_2/src/public/html/files/list.html @@ -0,0 +1,7 @@ +{{ define "title"}} + 222 +{{ end }} + +{{ define "content" }} +

List Content

+{{ end }} \ No newline at end of file diff --git a/_examples/view/template_blocks_2/src/public/html/layouts/main.html b/_examples/view/template_blocks_2/src/public/html/layouts/main.html new file mode 100644 index 00000000..22501f28 --- /dev/null +++ b/_examples/view/template_blocks_2/src/public/html/layouts/main.html @@ -0,0 +1,8 @@ + + + {{ block "title" .}}Main Default Title{{end}} + + + {{ block "content" .}}

Main Default Content

{{end}} + + \ No newline at end of file diff --git a/_examples/view/template_blocks_2/src/public/html/layouts/secondary.html b/_examples/view/template_blocks_2/src/public/html/layouts/secondary.html new file mode 100644 index 00000000..0bfda42d --- /dev/null +++ b/_examples/view/template_blocks_2/src/public/html/layouts/secondary.html @@ -0,0 +1,9 @@ + + + {{ block "title" .}}Secondary Default Title{{end}} + + +

Secondary Layout

+ {{ block "content" .}}

Secondary Default Content

{{end}} + + \ No newline at end of file diff --git a/_examples/view/template_blocks_2/src/public/html/menu/menu.html b/_examples/view/template_blocks_2/src/public/html/menu/menu.html new file mode 100644 index 00000000..a9880027 --- /dev/null +++ b/_examples/view/template_blocks_2/src/public/html/menu/menu.html @@ -0,0 +1,3 @@ +{{ define "title" }} 111{{ end }} + +{{ define "content" }}

Menu Content

{{ end }} \ No newline at end of file diff --git a/aliases.go b/aliases.go index 54061600..1acea298 100644 --- a/aliases.go +++ b/aliases.go @@ -336,18 +336,18 @@ func ConfigureMiddleware(handlers ...Handler) router.PartyConfigurator { return &partyConfiguratorMiddleware{handlers: handlers} } -var ( - // Compression is a middleware which enables - // writing and reading using the best offered compression. - // Usage: - // app.Use (for matched routes) - // app.UseRouter (for both matched and 404s or other HTTP errors). - Compression = func(ctx Context) { - ctx.CompressWriter(true) - ctx.CompressReader(true) - ctx.Next() - } +// Compression is a middleware which enables +// writing and reading using the best offered compression. +// Usage: +// app.Use (for matched routes) +// app.UseRouter (for both matched and 404s or other HTTP errors). +func Compression(ctx Context) { + ctx.CompressWriter(true) + ctx.CompressReader(true) + ctx.Next() +} +var ( // AllowQuerySemicolons returns a middleware that serves requests by converting any // unescaped semicolons(;) in the URL query to ampersands(&). // diff --git a/core/router/api_builder.go b/core/router/api_builder.go index c2b84813..26f1e62f 100644 --- a/core/router/api_builder.go +++ b/core/router/api_builder.go @@ -754,6 +754,13 @@ func (api *APIBuilder) createRoutes(errorCode int, methods []string, relativePat mainHandlerFileName, mainHandlerFileNumber := context.HandlerFileLineRel(handlers[mainHandlerIndex]) + // TODO: think of it. + if mainHandlerFileName == "" { + // At PartyConfigure, 2nd+ level of routes it will get but in reallity will be the same as the caller. + mainHandlerFileName = filename + mainHandlerFileNumber = line + } + // re-calculate mainHandlerIndex in favor of the middlewares. mainHandlerIndex = len(beginHandlers) + mainHandlerIndex diff --git a/core/router/handler.go b/core/router/handler.go index 024d0f52..131fcd5e 100644 --- a/core/router/handler.go +++ b/core/router/handler.go @@ -2,13 +2,11 @@ package router import ( "errors" - "fmt" "net/http" "sort" "strings" "sync" "sync/atomic" - "time" "github.com/kataras/iris/v12/context" "github.com/kataras/iris/v12/core/errgroup" @@ -16,7 +14,6 @@ import ( macroHandler "github.com/kataras/iris/v12/macro/handler" "github.com/kataras/golog" - "github.com/kataras/pio" ) type ( @@ -371,87 +368,7 @@ func (h *routerHandler) Build(provider RoutesProvider) error { } } - // TODO: move this and make it easier to read when all cases are, visually, tested. - if logger := h.logger; logger != nil && logger.Level == golog.DebugLevel && noLogCount < len(registeredRoutes) { - // group routes by method and print them without the [DBUG] and time info, - // the route logs are colorful. - // Note: don't use map, we need to keep registered order, use - // different slices for each method. - - collect := func(method string) (methodRoutes []*Route) { - for _, r := range registeredRoutes { - if r.NoLog { - continue - } - if r.Method == method { - methodRoutes = append(methodRoutes, r) - } - } - - return - } - - type MethodRoutes struct { - method string - routes []*Route - } - - allMethods := append(AllMethods, []string{MethodNone, ""}...) - methodRoutes := make([]MethodRoutes, 0, len(allMethods)) - - for _, method := range allMethods { - routes := collect(method) - if len(routes) > 0 { - methodRoutes = append(methodRoutes, MethodRoutes{method, routes}) - } - } - - if n := len(methodRoutes); n > 0 { - tr := "routes" - if len(registeredRoutes) == 1 { - tr = tr[0 : len(tr)-1] - } - - bckpNewLine := logger.NewLine - logger.NewLine = false - debugLevel := golog.Levels[golog.DebugLevel] - // Replace that in order to not transfer it to the log handler (e.g. json) - // logger.Debugf("API: %d registered %s (", len(registeredRoutes), tr) - // with: - pio.WriteRich(logger.Printer, debugLevel.Title, debugLevel.ColorCode, debugLevel.Style...) - fmt.Fprintf(logger.Printer, " %s %sAPI: %d registered %s (", time.Now().Format(logger.TimeFormat), logger.Prefix, len(registeredRoutes)-noLogCount, tr) - // - logger.NewLine = bckpNewLine - - for i, m := range methodRoutes { - // @method: @count - if i > 0 { - if i == n-1 { - fmt.Fprint(logger.Printer, " and ") - } else { - fmt.Fprint(logger.Printer, ", ") - } - } - if m.method == "" { - m.method = "ERROR" - } - fmt.Fprintf(logger.Printer, "%d ", len(m.routes)) - pio.WriteRich(logger.Printer, m.method, TraceTitleColorCode(m.method)) - } - - fmt.Fprint(logger.Printer, ")\n") - } - - for i, m := range methodRoutes { - for _, r := range m.routes { - r.Trace(logger.Printer, -1) - } - - if i != len(allMethods)-1 { - logger.Printer.Write(pio.NewLine) - } - } - } + printRoutesInfo(h.logger, registeredRoutes, noLogCount) return errgroup.Check(rp) } diff --git a/core/router/handler_debug.go b/core/router/handler_debug.go new file mode 100644 index 00000000..6081c7ac --- /dev/null +++ b/core/router/handler_debug.go @@ -0,0 +1,94 @@ +package router + +import ( + "fmt" + "time" + + "github.com/kataras/golog" + "github.com/kataras/pio" +) + +func printRoutesInfo(logger *golog.Logger, registeredRoutes []*Route, noLogCount int) { + if !(logger != nil && logger.Level == golog.DebugLevel && noLogCount < len(registeredRoutes)) { + return + } + + // group routes by method and print them without the [DBUG] and time info, + // the route logs are colorful. + // Note: don't use map, we need to keep registered order, use + // different slices for each method. + + collect := func(method string) (methodRoutes []*Route) { + for _, r := range registeredRoutes { + if r.NoLog { + continue + } + if r.Method == method { + methodRoutes = append(methodRoutes, r) + } + } + + return + } + + type MethodRoutes struct { + method string + routes []*Route + } + + allMethods := append(AllMethods, []string{MethodNone, ""}...) + methodRoutes := make([]MethodRoutes, 0, len(allMethods)) + + for _, method := range allMethods { + routes := collect(method) + if len(routes) > 0 { + methodRoutes = append(methodRoutes, MethodRoutes{method, routes}) + } + } + + if n := len(methodRoutes); n > 0 { + tr := "routes" + if len(registeredRoutes) == 1 { + tr = tr[0 : len(tr)-1] + } + + bckpNewLine := logger.NewLine + logger.NewLine = false + debugLevel := golog.Levels[golog.DebugLevel] + // Replace that in order to not transfer it to the log handler (e.g. json) + // logger.Debugf("API: %d registered %s (", len(registeredRoutes), tr) + // with: + pio.WriteRich(logger.Printer, debugLevel.Title, debugLevel.ColorCode, debugLevel.Style...) + fmt.Fprintf(logger.Printer, " %s %sAPI: %d registered %s (", time.Now().Format(logger.TimeFormat), logger.Prefix, len(registeredRoutes)-noLogCount, tr) + // + logger.NewLine = bckpNewLine + + for i, m := range methodRoutes { + // @method: @count + if i > 0 { + if i == n-1 { + fmt.Fprint(logger.Printer, " and ") + } else { + fmt.Fprint(logger.Printer, ", ") + } + } + if m.method == "" { + m.method = "ERROR" + } + fmt.Fprintf(logger.Printer, "%d ", len(m.routes)) + pio.WriteRich(logger.Printer, m.method, TraceTitleColorCode(m.method)) + } + + fmt.Fprint(logger.Printer, ")\n") + } + + for i, m := range methodRoutes { + for _, r := range m.routes { + r.Trace(logger.Printer, -1) + } + + if i != len(allMethods)-1 { + logger.Printer.Write(pio.NewLine) + } + } +} diff --git a/core/router/route.go b/core/router/route.go index 457a28cd..34d8684a 100644 --- a/core/router/route.go +++ b/core/router/route.go @@ -562,6 +562,14 @@ func (r *Route) Trace(w io.Writer, stoppedIndex int) { file, line = context.HandlerFileLineRel(h) // If a middleware, e.g (macro) which changes the main handler index, // skip it. + + // TODO: think of it. + if file == "" { + // At PartyConfigure, 2nd+ level of routes it will get but in reallity will be the same as the caller. + file = r.RegisterFileName + line = r.RegisterLineNumber + } + if file == r.SourceFileName && line == r.SourceLineNumber { continue } diff --git a/go.mod b/go.mod index 5128f6f0..c787da32 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/iris-contrib/httpexpect/v2 v2.15.2 github.com/iris-contrib/schema v0.0.6 github.com/json-iterator/go v1.1.12 - github.com/kataras/blocks v0.0.7 + github.com/kataras/blocks v0.0.8 github.com/kataras/golog v0.1.9 github.com/kataras/jwt v0.1.10 github.com/kataras/neffos v0.0.22 @@ -107,6 +107,7 @@ require ( github.com/yudai/gojsondiff v1.0.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect moul.io/http2curl/v2 v2.3.0 // indirect ) diff --git a/go.sum b/go.sum index 3c6eaa82..11444c37 100644 --- a/go.sum +++ b/go.sum @@ -105,8 +105,8 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4= -github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I= +github.com/kataras/blocks v0.0.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM= +github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg= github.com/kataras/golog v0.1.9 h1:vLvSDpP7kihFGKFAvBSofYo7qZNULYSHOH2D7rPTKJk= github.com/kataras/golog v0.1.9/go.mod h1:jlpk/bOaYCyqDqH18pgDHdaJab72yBE6i0O3s30hpWY= github.com/kataras/jwt v0.1.10 h1:GBXOF9RVInDPhCFBiDumRG9Tt27l7ugLeLo8HL5SeKQ= @@ -263,6 +263,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= diff --git a/sessions/config.go b/sessions/config.go index fad2eeab..d7c8c97a 100644 --- a/sessions/config.go +++ b/sessions/config.go @@ -46,6 +46,9 @@ type ( // Expires the duration of which the cookie must expires (created_time.Add(Expires)). // If you want to delete the cookie when the browser closes, set it to -1. + // However, if you use a database storage setting this value to -1 may + // cause you problems because of the fact that the database + // may has its own expiration mechanism and value will be expired and removed immediately. // // 0 means no expire, (24 years) // -1 means when browser closes