mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
Fix mail send, complete jade support, fix iriscontrol index , replace iriscontrol session to basicauth
This commit is contained in:
parent
91b45ebfdb
commit
48aaca5bc0
10
HISTORY.md
10
HISTORY.md
|
@ -1,5 +1,15 @@
|
|||
# History
|
||||
|
||||
## 3.0.0-beta.2 -> 3.0.0-beta.3
|
||||
|
||||
- Complete the Jade Template Engine support, {{ render }} and {{ url }} done also.
|
||||
|
||||
- Fix Mail().Send
|
||||
|
||||
- Iriscontrol plugin: Replace login using session to basic authentication
|
||||
|
||||
And other not-too-important fixes
|
||||
|
||||
## 3.0.0-beta -> 3.0.0-beta.2
|
||||
|
||||
- NEW: Wildcard(dynamic) subdomains, read [here](https://kataras.gitbooks.io/iris/content/subdomains.html)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
[Travis]: http://travis-ci.org/kataras/iris
|
||||
[License Widget]: https://img.shields.io/badge/license-Apache%20License%202.0-E91E63.svg?style=flat-square
|
||||
[License]: https://github.com/kataras/iris/blob/master/LICENSE
|
||||
[Release Widget]: https://img.shields.io/badge/release-v3.0.0--beta.2-blue.svg?style=flat-square
|
||||
[Release Widget]: https://img.shields.io/badge/release-v3.0.0--beta.3-blue.svg?style=flat-square
|
||||
[Release]: https://github.com/kataras/iris/releases
|
||||
[Gitter Widget]: https://img.shields.io/badge/chat-on%20gitter-00BCD4.svg?style=flat-square
|
||||
[Gitter]: https://gitter.im/kataras/iris
|
||||
|
@ -116,7 +116,7 @@ Iris suggests you to use [this](https://github.com/gavv/httpexpect) new suite t
|
|||
Versioning
|
||||
------------
|
||||
|
||||
Current: **v3.0.0-beta.2**
|
||||
Current: **v3.0.0-beta.3**
|
||||
> Iris is an active project
|
||||
|
||||
|
||||
|
|
|
@ -104,13 +104,13 @@ type (
|
|||
|
||||
// HTMLTemplate contains specific configs for HTMLTemplate standard html/template
|
||||
HTMLTemplate HTMLTemplate
|
||||
// Pongo contains specific configs for for pongo2
|
||||
// Jade contains specific configs for Jade
|
||||
Jade Jade
|
||||
// Pongo contains specific configs for pongo2
|
||||
Pongo Pongo
|
||||
// Markdown contains specific configs for for markdown
|
||||
// Markdown contains specific configs for markdown
|
||||
// this doesn't supports Layout & binding context
|
||||
Markdown Markdown
|
||||
// Jade contains specific configs for jade
|
||||
Jade Jade
|
||||
// Amber contains specific configs for amber
|
||||
Amber Amber
|
||||
}
|
||||
|
@ -132,6 +132,8 @@ type (
|
|||
// these can override the Funcs inside no-layout templates also, use it when you know what you're doing
|
||||
LayoutFuncs map[string]interface{}
|
||||
}
|
||||
// Jade the configs for JadeEngine
|
||||
Jade HTMLTemplate
|
||||
// Pongo the configs for PongoEngine
|
||||
Pongo struct {
|
||||
// Filters for pongo2, map[name of the filter] the filter function . The filters are auto register
|
||||
|
@ -145,17 +147,6 @@ type (
|
|||
Sanitize bool // if true then returns safe html, default is false
|
||||
}
|
||||
|
||||
// Jade the configs for JadeEngine
|
||||
Jade struct {
|
||||
// Funcs like html/template
|
||||
Funcs map[string]interface{}
|
||||
// LayoutFuncs like html/template
|
||||
// the difference from Funcs is that these funcs
|
||||
// can be used inside a layout and can override the predefined (yield,partial...) or add more custom funcs
|
||||
// these can override the Funcs inside no-layout templates also, use it when you know what you're doing
|
||||
LayoutFuncs map[string]interface{}
|
||||
}
|
||||
|
||||
// Amber the configs for AmberEngine
|
||||
Amber struct {
|
||||
// Funcs for the html/template result, amber default funcs are not overrided so use it without worries
|
||||
|
@ -213,10 +204,10 @@ func DefaultTemplate() Template {
|
|||
Charset: "UTF-8",
|
||||
Layout: "", // currently this is the only config which not working for pongo2 yet but I will find a way
|
||||
HTMLTemplate: HTMLTemplate{Left: "{{", Right: "}}", Funcs: make(map[string]interface{}, 0), LayoutFuncs: make(map[string]interface{}, 0)},
|
||||
Jade: Jade{Left: "{{", Right: "}}", Funcs: make(map[string]interface{}, 0), LayoutFuncs: make(map[string]interface{}, 0)},
|
||||
Pongo: Pongo{Filters: make(map[string]pongo2.FilterFunction, 0), Globals: make(map[string]interface{}, 0)},
|
||||
Markdown: Markdown{Sanitize: false},
|
||||
Amber: Amber{Funcs: template.FuncMap{}},
|
||||
Jade: Jade{Funcs: template.FuncMap{}, LayoutFuncs: template.FuncMap{}},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
87
iris.go
87
iris.go
|
@ -1,4 +1,4 @@
|
|||
// Package iris v3.0.0-beta.2
|
||||
// Package iris the fastest golang web framework, so far.
|
||||
//
|
||||
// Note: When 'Station', we mean the Iris type.
|
||||
package iris
|
||||
|
@ -11,7 +11,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/flosch/pongo2"
|
||||
"github.com/kataras/iris/config"
|
||||
"github.com/kataras/iris/logger"
|
||||
"github.com/kataras/iris/mail"
|
||||
|
@ -30,7 +29,7 @@ import (
|
|||
|
||||
const (
|
||||
// Version of the iris
|
||||
Version = "v3.0.0-beta.2"
|
||||
Version = "v3.0.0-beta.3"
|
||||
banner = ` _____ _
|
||||
|_ _| (_)
|
||||
| | ____ _ ___
|
||||
|
@ -113,85 +112,17 @@ func (s *Iris) newContextPool() sync.Pool {
|
|||
}}
|
||||
}
|
||||
|
||||
///TODO HERE MOVE THEM SOMEWHERE ELSE OR MAKE IT MORE BUETY->
|
||||
func (s *Iris) initTemplates() {
|
||||
if s.templates == nil { // because if .Templates() called before server's listen, s.templates != nil when PreListen
|
||||
// init the templates
|
||||
|
||||
// set the custom iris-direct-integration functions, layout and no-layout if HTMLEngine is used
|
||||
templateConfig := &s.config.Render.Template
|
||||
///TODO gia AMber episis
|
||||
if templateConfig.Engine == config.HTMLEngine || templateConfig.Engine == config.AmberEngine {
|
||||
funcs := map[string]interface{}{
|
||||
|
||||
"url": func(routeName string, args ...interface{}) (string, error) {
|
||||
r := s.RouteByName(routeName)
|
||||
// check if not found
|
||||
if r.GetMethod() == "" {
|
||||
return "", ErrRenderRouteNotFound.Format(routeName)
|
||||
template.RegisterSharedFunc("url", func(routeName string, args ...interface{}) string {
|
||||
if url, err := s.UriOf(routeName, args...); err == nil {
|
||||
return url
|
||||
} else {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return r.ParseURI(args...), nil
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
// these should be already a non-nil map but if .New(cfg) it's not, is mergo's bug, temporary:
|
||||
if templateConfig.Engine == config.HTMLEngine {
|
||||
if templateConfig.HTMLTemplate.LayoutFuncs == nil {
|
||||
templateConfig.HTMLTemplate.LayoutFuncs = make(map[string]interface{}, len(funcs))
|
||||
}
|
||||
|
||||
if templateConfig.HTMLTemplate.Funcs == nil {
|
||||
templateConfig.HTMLTemplate.Funcs = make(map[string]interface{}, len(funcs))
|
||||
}
|
||||
|
||||
for k, v := range funcs {
|
||||
// we don't want to override the user's LayoutFuncs, user should be able to override anything.
|
||||
if templateConfig.HTMLTemplate.LayoutFuncs[k] == nil {
|
||||
templateConfig.HTMLTemplate.LayoutFuncs[k] = v
|
||||
}
|
||||
|
||||
if templateConfig.HTMLTemplate.Funcs[k] == nil {
|
||||
templateConfig.HTMLTemplate.Funcs[k] = v
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if templateConfig.Engine == config.AmberEngine {
|
||||
if templateConfig.Amber.Funcs == nil {
|
||||
templateConfig.Amber.Funcs = make(map[string]interface{}, len(funcs))
|
||||
}
|
||||
|
||||
for k, v := range funcs {
|
||||
if templateConfig.Amber.Funcs[k] == nil {
|
||||
templateConfig.Amber.Funcs[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
} else if templateConfig.Engine == config.PongoEngine {
|
||||
if templateConfig.Pongo.Globals == nil {
|
||||
templateConfig.Pongo.Globals = make(map[string]interface{}, 1)
|
||||
}
|
||||
|
||||
urlFunc := func(routeName string, args ...interface{}) (out *pongo2.Value) {
|
||||
|
||||
r := s.RouteByName(routeName)
|
||||
// check if not found
|
||||
if r.GetMethod() == "" {
|
||||
return pongo2.AsValue(ErrRenderRouteNotFound.Format(routeName).Error())
|
||||
}
|
||||
|
||||
return pongo2.AsValue(r.ParseURI(args...))
|
||||
}
|
||||
|
||||
// register it to the global context, no as Filter.
|
||||
templateConfig.Pongo.Globals["url"] = urlFunc
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
s.templates = template.New(s.config.Render.Template)
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
package mail
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/kataras/iris/config"
|
||||
"github.com/kataras/iris/utils"
|
||||
)
|
||||
|
||||
const tmpl = `From: {{.From}}<br /> To: {{.To}}<br /> Subject: {{.Subject}}<br /> MIME-version: 1.0<br /> Content-Type: text/html; charset="UTF-8"<br /> <br /> {{.Body}}`
|
||||
|
||||
var buf = utils.NewBufferPool(64)
|
||||
|
||||
type (
|
||||
|
@ -24,6 +23,7 @@ type (
|
|||
|
||||
mailer struct {
|
||||
config config.Mail
|
||||
fromAddr mail.Address
|
||||
auth smtp.Auth
|
||||
authenticated bool
|
||||
}
|
||||
|
@ -31,7 +31,14 @@ type (
|
|||
|
||||
// New creates and returns a new Service
|
||||
func New(cfg config.Mail) Service {
|
||||
return &mailer{config: cfg}
|
||||
m := &mailer{config: cfg}
|
||||
|
||||
// not necessary
|
||||
if !cfg.UseCommand && cfg.Username != "" && strings.Contains(cfg.Username, "@") {
|
||||
m.fromAddr = mail.Address{cfg.Username[0:strings.IndexByte(cfg.Username, '@')], cfg.Username}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// Send sends a mail to recipients
|
||||
|
@ -56,19 +63,31 @@ func (m *mailer) sendSMTP(to []string, subject, body string) error {
|
|||
m.authenticated = true
|
||||
}
|
||||
|
||||
mailArgs := map[string]string{"To": strings.Join(to, ","), "Subject": subject, "Body": body}
|
||||
template := template.Must(template.New("mailTmpl").Parse(tmpl))
|
||||
fullhost := fmt.Sprintf("%s:%d", m.config.Host, m.config.Port)
|
||||
|
||||
if err := template.Execute(buffer, mailArgs); err != nil {
|
||||
return err
|
||||
/* START: This one helped me https://gist.github.com/andelf/5004821 */
|
||||
header := make(map[string]string)
|
||||
header["From"] = m.fromAddr.String()
|
||||
header["To"] = strings.Join(to, ",")
|
||||
header["Subject"] = subject
|
||||
header["MIME-Version"] = "1.0"
|
||||
header["Content-Type"] = "text/html; charset=\"utf-8\""
|
||||
header["Content-Transfer-Encoding"] = "base64"
|
||||
|
||||
message := ""
|
||||
for k, v := range header {
|
||||
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
||||
}
|
||||
message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
|
||||
|
||||
/* END */
|
||||
|
||||
return smtp.SendMail(
|
||||
fmt.Sprintf("%s:%d", m.config.Host, m.config.Port),
|
||||
fmt.Sprintf(fullhost),
|
||||
m.auth,
|
||||
m.config.Username,
|
||||
to,
|
||||
buffer.Bytes(),
|
||||
[]byte(message),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -26,13 +26,15 @@ func (i *irisControlPlugin) startControlPanel() {
|
|||
}
|
||||
|
||||
i.server = iris.New()
|
||||
i.server.Config().DisableBanner = true
|
||||
i.server.Config().Render.Template.Directory = installationPath + "templates"
|
||||
//i.server.SetRenderConfig(i.server.Config.Render)
|
||||
i.setPluginsInfo()
|
||||
i.setPanelRoutes()
|
||||
|
||||
go i.server.Listen(strconv.Itoa(i.options.Port))
|
||||
i.pluginContainer.Printf("[%s] %s is running at port %d with %d authenticated users", time.Now().UTC().String(), Name, i.options.Port, len(i.auth.authenticatedUsers))
|
||||
|
||||
i.pluginContainer.Printf("[%s] %s is running at port %d", time.Now().UTC().String(), Name, i.options.Port)
|
||||
|
||||
}
|
||||
|
||||
|
@ -67,21 +69,10 @@ func (i *irisControlPlugin) installAssets() (err error) {
|
|||
func (i *irisControlPlugin) setPanelRoutes() {
|
||||
|
||||
i.server.Static("/public", installationPath+"static", 1)
|
||||
i.server.Get("/login", func(ctx *iris.Context) {
|
||||
ctx.Render("login", nil)
|
||||
})
|
||||
|
||||
i.server.Post("/login", func(ctx *iris.Context) {
|
||||
i.auth.login(ctx)
|
||||
})
|
||||
|
||||
i.server.Use(i.auth)
|
||||
i.server.Use(i.authFunc)
|
||||
i.server.Get("/", func(ctx *iris.Context) {
|
||||
ctx.Render("index", DashboardPage{ServerIsRunning: i.station.Server().IsListening(), Routes: i.routes.All(), Plugins: i.plugins})
|
||||
})
|
||||
|
||||
i.server.Post("/logout", func(ctx *iris.Context) {
|
||||
i.auth.logout(ctx)
|
||||
ctx.Render("index.html", DashboardPage{ServerIsRunning: i.station.Server().IsListening(), Routes: i.routes.All(), Plugins: i.plugins})
|
||||
})
|
||||
|
||||
//the controls
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/config"
|
||||
"github.com/kataras/iris/middleware/basicauth"
|
||||
"github.com/kataras/iris/plugin/routesinfo"
|
||||
"github.com/kataras/iris/server"
|
||||
)
|
||||
|
@ -29,7 +30,7 @@ type irisControlPlugin struct {
|
|||
plugins []PluginInfo
|
||||
//
|
||||
|
||||
auth *userAuth
|
||||
authFunc iris.HandlerFunc
|
||||
}
|
||||
|
||||
// New returns the plugin which is ready-to-use inside iris.Plugin method
|
||||
|
@ -39,12 +40,13 @@ func New(cfg ...config.IrisControl) iris.IPlugin {
|
|||
if len(cfg) > 0 {
|
||||
c = cfg[0]
|
||||
}
|
||||
auth := newUserAuth(c.Users)
|
||||
if auth == nil {
|
||||
if c.Users == nil || len(c.Users) == 0 {
|
||||
panic(Name + " Error: you should pass authenticated users map to the options, refer to the docs!")
|
||||
}
|
||||
|
||||
return &irisControlPlugin{options: c, auth: auth, routes: routesinfo.RoutesInfo()}
|
||||
auth := basicauth.Default(c.Users)
|
||||
|
||||
return &irisControlPlugin{options: c, authFunc: auth, routes: routesinfo.RoutesInfo()}
|
||||
}
|
||||
|
||||
// Web set the options for the plugin and return the plugin which is ready-to-use inside iris.Plugin method
|
||||
|
@ -106,7 +108,6 @@ func (i *irisControlPlugin) Destroy() {
|
|||
i.station = nil
|
||||
i.server.Close()
|
||||
i.pluginContainer = nil
|
||||
i.auth.Destroy()
|
||||
i.auth = nil
|
||||
i.authFunc = nil
|
||||
i.pluginContainer.Printf("[%s] %s is turned off", time.Now().UTC().String(), Name)
|
||||
}
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
package iriscontrol
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/sessions"
|
||||
// _ empty because it auto-registers
|
||||
_ "github.com/kataras/iris/sessions/providers/memory"
|
||||
)
|
||||
|
||||
var panelSessions *sessions.Manager
|
||||
|
||||
func init() {
|
||||
//using the default
|
||||
panelSessions = sessions.New()
|
||||
}
|
||||
|
||||
type user struct {
|
||||
username string
|
||||
password string
|
||||
}
|
||||
type userAuth struct {
|
||||
authenticatedUsers []user
|
||||
}
|
||||
|
||||
// newUserAuth returns a new userAuth object, parameter is the authenticated users as map
|
||||
func newUserAuth(usersMap map[string]string) *userAuth {
|
||||
if usersMap != nil {
|
||||
obj := &userAuth{make([]user, 0)}
|
||||
for key, val := range usersMap {
|
||||
obj.authenticatedUsers = append(obj.authenticatedUsers, user{key, val})
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *userAuth) login(ctx *iris.Context) {
|
||||
session := panelSessions.Start(ctx)
|
||||
|
||||
username := ctx.PostFormValue("username")
|
||||
password := ctx.PostFormValue("password")
|
||||
|
||||
for _, authenticatedUser := range u.authenticatedUsers {
|
||||
if authenticatedUser.username == username && authenticatedUser.password == password {
|
||||
session.Set("username", username)
|
||||
session.Set("password", password)
|
||||
ctx.Write("success")
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.Write("fail")
|
||||
|
||||
}
|
||||
|
||||
func (u *userAuth) logout(ctx *iris.Context) {
|
||||
session := panelSessions.Start(ctx)
|
||||
session.Set("user", nil)
|
||||
|
||||
ctx.Redirect("/login")
|
||||
}
|
||||
|
||||
// check if session stored, then check if this user is the correct, each time, then continue, else not
|
||||
func (u *userAuth) Serve(ctx *iris.Context) {
|
||||
if ctx.PathString() == "/login" || strings.HasPrefix(ctx.PathString(), "/public") {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
session := panelSessions.Start(ctx)
|
||||
|
||||
if sessionVal := session.Get("username"); sessionVal != nil {
|
||||
username := sessionVal.(string)
|
||||
password := session.GetString("password")
|
||||
if username != "" && password != "" {
|
||||
|
||||
for _, authenticatedUser := range u.authenticatedUsers {
|
||||
if authenticatedUser.username == username && authenticatedUser.password == password {
|
||||
ctx.Next()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//if not logged in the redirect to the /login
|
||||
ctx.Redirect("/login")
|
||||
|
||||
}
|
||||
|
||||
// Destroy this is called on PreClose by the iriscontrol.go
|
||||
func (u *userAuth) Destroy() {
|
||||
|
||||
}
|
|
@ -10,20 +10,15 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Joker/jade"
|
||||
"github.com/kataras/iris/config"
|
||||
)
|
||||
|
||||
type (
|
||||
// Engine the html/template engine
|
||||
// Engine the html/template engine & Jade
|
||||
Engine struct {
|
||||
Config *config.Template
|
||||
Templates *template.Template
|
||||
// Middleware
|
||||
// Note:
|
||||
// I see that many template engines returns html/template as result
|
||||
// so I decided that the HTMLTemplate should accept a middleware for the final string content will be parsed to the main *html/template.Template
|
||||
// for example user of this property is Jade, currently
|
||||
Middleware func(string, string) (string, error)
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -36,7 +31,7 @@ var emptyFuncs = template.FuncMap{
|
|||
},
|
||||
"current": func() (string, error) {
|
||||
return "", nil
|
||||
}, "render": func(string) (string, error) {
|
||||
}, "render": func() (string, error) {
|
||||
return "", nil
|
||||
},
|
||||
}
|
||||
|
@ -73,7 +68,6 @@ func (s *Engine) buildFromDir() error {
|
|||
dir := s.Config.Directory
|
||||
s.Templates = template.New(dir)
|
||||
s.Templates.Delims(s.Config.HTMLTemplate.Left, s.Config.HTMLTemplate.Right)
|
||||
hasMiddleware := s.Middleware != nil
|
||||
// Walk the supplied directory and compile any files that match our extension list.
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if info == nil || info.IsDir() {
|
||||
|
@ -107,8 +101,8 @@ func (s *Engine) buildFromDir() error {
|
|||
name := filepath.ToSlash(rel)
|
||||
tmpl := s.Templates.New(name)
|
||||
|
||||
if hasMiddleware {
|
||||
contents, err = s.Middleware(name, contents)
|
||||
if s.Config.Engine == config.JadeEngine {
|
||||
contents, err = jade.Parse(name, contents)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -117,11 +111,11 @@ func (s *Engine) buildFromDir() error {
|
|||
}
|
||||
|
||||
// Add our funcmaps.
|
||||
//if s.Config.HTMLTemplate.Funcs != nil {
|
||||
// tmpl.Funcs(s.Config.HTMLTemplate.Funcs)
|
||||
//}
|
||||
if s.Config.HTMLTemplate.Funcs != nil {
|
||||
tmpl.Funcs(s.Config.HTMLTemplate.Funcs)
|
||||
}
|
||||
|
||||
tmpl.Funcs(s.Config.HTMLTemplate.Funcs).Parse(contents)
|
||||
tmpl.Funcs(emptyFuncs).Parse(contents)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -159,16 +153,20 @@ func (s *Engine) buildFromAsset() error {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
contents := string(buf)
|
||||
name := filepath.ToSlash(rel)
|
||||
tmpl := s.Templates.New(name)
|
||||
|
||||
// Add our funcmaps.
|
||||
//for _, funcs := range s.Config.HTMLTemplate.Funcs {
|
||||
/*if s.Config.HTMLTemplate.Funcs != nil {
|
||||
tmpl.Funcs(s.Config.HTMLTemplate.Funcs)
|
||||
}*/
|
||||
if s.Config.Engine == config.JadeEngine {
|
||||
contents, err = jade.Parse(name, contents)
|
||||
}
|
||||
|
||||
tmpl.Funcs(emptyFuncs).Funcs(s.Config.HTMLTemplate.Funcs).Parse(string(buf))
|
||||
// Add our funcmaps.
|
||||
if s.Config.HTMLTemplate.Funcs != nil {
|
||||
tmpl.Funcs(s.Config.HTMLTemplate.Funcs)
|
||||
}
|
||||
|
||||
tmpl.Funcs(emptyFuncs).Parse(contents)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -178,25 +176,11 @@ func (s *Engine) buildFromAsset() error {
|
|||
|
||||
func (s *Engine) executeTemplateBuf(name string, binding interface{}) (*bytes.Buffer, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
/*
|
||||
var err error
|
||||
if s.Middleware != nil {
|
||||
contents, err := s.Middleware(name, buf.String())
|
||||
if err != nil {
|
||||
return buf, err
|
||||
}
|
||||
buf.WriteString(contents)
|
||||
}
|
||||
*/
|
||||
err := s.Templates.ExecuteTemplate(buf, name, binding)
|
||||
|
||||
return buf, err
|
||||
}
|
||||
|
||||
func (s *Engine) ExecuteTemplateBuf(name string, binding interface{}) (*bytes.Buffer, error) {
|
||||
return s.executeTemplateBuf(name, binding)
|
||||
}
|
||||
|
||||
func (s *Engine) layoutFuncsFor(name string, binding interface{}) {
|
||||
funcs := template.FuncMap{
|
||||
"yield": func() (template.HTML, error) {
|
||||
|
@ -211,15 +195,12 @@ func (s *Engine) layoutFuncsFor(name string, binding interface{}) {
|
|||
fullPartialName := fmt.Sprintf("%s-%s", partialName, name)
|
||||
if s.Config.HTMLTemplate.RequirePartials || s.Templates.Lookup(fullPartialName) != nil {
|
||||
buf, err := s.executeTemplateBuf(fullPartialName, binding)
|
||||
// Return safe HTML here since we are rendering our own template.
|
||||
return template.HTML(buf.String()), err
|
||||
}
|
||||
return "", nil
|
||||
},
|
||||
"render": func(fullPartialName string) (template.HTML, error) {
|
||||
buf, err := s.executeTemplateBuf(fullPartialName, binding)
|
||||
println("html.go:217-> " + buf.String())
|
||||
// Return safe HTML here since we are rendering our own template.
|
||||
return template.HTML(buf.String()), err
|
||||
},
|
||||
}
|
||||
|
@ -234,12 +215,28 @@ func (s *Engine) layoutFuncsFor(name string, binding interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Engine) runtimeFuncsFor(name string, binding interface{}) {
|
||||
funcs := template.FuncMap{
|
||||
"render": func(fullPartialName string) (template.HTML, error) {
|
||||
buf, err := s.executeTemplateBuf(fullPartialName, binding)
|
||||
return template.HTML(buf.String()), err
|
||||
},
|
||||
}
|
||||
|
||||
if tpl := s.Templates.Lookup(name); tpl != nil {
|
||||
tpl.Funcs(funcs)
|
||||
}
|
||||
}
|
||||
|
||||
// ExecuteWriter executes a templates and write its results to the out writer
|
||||
func (s *Engine) ExecuteWriter(out io.Writer, name string, binding interface{}, layout string) error {
|
||||
if layout != "" && layout != config.NoLayout {
|
||||
name = layout
|
||||
}
|
||||
s.layoutFuncsFor(name, binding)
|
||||
name = layout
|
||||
|
||||
} else {
|
||||
s.runtimeFuncsFor(name, binding)
|
||||
}
|
||||
|
||||
return s.Templates.ExecuteTemplate(out, name, binding)
|
||||
}
|
||||
|
|
|
@ -1,24 +1,15 @@
|
|||
// Package jade the JadeEngine's functionality lives inside ../html now
|
||||
package jade
|
||||
|
||||
import (
|
||||
"github.com/Joker/jade"
|
||||
"github.com/kataras/iris/config"
|
||||
"github.com/kataras/iris/render/template/engine/html"
|
||||
)
|
||||
|
||||
// Engine the JadeEngine
|
||||
type Engine struct {
|
||||
*html.Engine
|
||||
}
|
||||
|
||||
// New creates and returns a new JadeEngine with its configs
|
||||
func New(cfg config.Template) *Engine {
|
||||
cfg.HTMLTemplate.Funcs = cfg.Jade.Funcs //copy the jade's funcs to the underline HTMLEngine
|
||||
cfg.HTMLTemplate.LayoutFuncs = cfg.Jade.LayoutFuncs
|
||||
underline := &Engine{Engine: html.New(cfg)}
|
||||
underline.Middleware = func(relativeName string, fileContents string) (string, error) {
|
||||
return jade.Parse(relativeName, fileContents)
|
||||
}
|
||||
|
||||
return underline
|
||||
// New creates and returns the HTMLTemplate template engine
|
||||
func New(c config.Template) *html.Engine {
|
||||
// copy the Jade to the HTMLTemplate
|
||||
c.HTMLTemplate = config.HTMLTemplate(c.Jade)
|
||||
s := &html.Engine{Config: &c}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -55,21 +55,48 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
// sharedFuncs the funcs should be exists in all supported view template engines
|
||||
var sharedFuncs map[string]interface{}
|
||||
|
||||
// we do this because we don't want to override the user's funcs
|
||||
func setSharedFuncs(source map[string]interface{}, target map[string]interface{}) {
|
||||
if source == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if target == nil {
|
||||
target = make(map[string]interface{}, len(source))
|
||||
}
|
||||
|
||||
for k, v := range source {
|
||||
if target[k] == nil {
|
||||
target[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New creates and returns a Template instance which keeps the Template Engine and helps with render
|
||||
func New(c config.Template) *Template {
|
||||
defer func() {
|
||||
sharedFuncs = nil
|
||||
}()
|
||||
|
||||
var e Engine
|
||||
// [ENGINE-2]
|
||||
switch c.Engine {
|
||||
case config.HTMLEngine:
|
||||
setSharedFuncs(sharedFuncs, c.HTMLTemplate.Funcs)
|
||||
e = html.New(c) // HTMLTemplate
|
||||
case config.JadeEngine:
|
||||
setSharedFuncs(sharedFuncs, c.Jade.Funcs)
|
||||
e = jade.New(c) // Jade
|
||||
case config.PongoEngine:
|
||||
setSharedFuncs(sharedFuncs, c.Pongo.Globals)
|
||||
e = pongo.New(c) // Pongo2
|
||||
case config.MarkdownEngine:
|
||||
e = markdown.New(c) // Markdown
|
||||
case config.JadeEngine:
|
||||
e = jade.New(c) // Jade
|
||||
case config.AmberEngine:
|
||||
setSharedFuncs(sharedFuncs, c.Amber.Funcs)
|
||||
e = amber.New(c) // Amber
|
||||
default: // config.NoEngine
|
||||
return nil
|
||||
|
@ -97,6 +124,14 @@ func New(c config.Template) *Template {
|
|||
|
||||
}
|
||||
|
||||
// RegisterSharedFunc registers a functionality that should be inherited from all supported template engines
|
||||
func RegisterSharedFunc(name string, fn interface{}) {
|
||||
if sharedFuncs == nil {
|
||||
sharedFuncs = make(map[string]interface{})
|
||||
}
|
||||
sharedFuncs[name] = fn
|
||||
}
|
||||
|
||||
// Render renders a template using the context's writer
|
||||
func (t *Template) Render(ctx context.IContext, name string, binding interface{}, layout ...string) (err error) {
|
||||
|
||||
|
|
21
router.go
21
router.go
|
@ -118,15 +118,32 @@ func (r *router) addRoute(route IRoute) {
|
|||
|
||||
// RouteByName returns a route by its name,if not found then returns a route with empty path
|
||||
// Note that the searching is case-sensitive
|
||||
func (r *router) RouteByName(lookUpName string) IRoute {
|
||||
func (r *router) RouteByName(routeName string) IRoute {
|
||||
for _, route := range r.lookups {
|
||||
if route.GetName() == lookUpName {
|
||||
if route.GetName() == routeName {
|
||||
return route
|
||||
}
|
||||
}
|
||||
return &Route{}
|
||||
}
|
||||
|
||||
// UriOf returns the parsed URI of a route
|
||||
// receives two parameters
|
||||
// the first is the route's name (string)
|
||||
// the second is a variadic, if the route is dynamic (receives named parameters) then pass the value of these parameters here
|
||||
// overview of the result is: scheme(http or https if ListenTLS)/yourhost.com:PORT/profile/theusername/friends/theid
|
||||
//
|
||||
// example /profile/:username/friends/:friendId with name "profile" -> .UriOf("profile","kataras",8) will give http://127.0.0.1:8080/profile/kataras/friends/8
|
||||
func (r *router) UriOf(routeName string, args ...interface{}) (string, error) {
|
||||
route := r.RouteByName(routeName)
|
||||
// check if not found
|
||||
if route.GetMethod() == "" {
|
||||
return "", ErrRenderRouteNotFound.Format(routeName)
|
||||
}
|
||||
|
||||
return route.ParseURI(args...), nil
|
||||
}
|
||||
|
||||
//check if any tree has cors setted to true, means that cors middleware is added
|
||||
func (r *router) cors() (has bool) {
|
||||
r.garden.visitAll(func(i int, tree *tree) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user