├── .gitignore ├── README.md ├── tags_xsrftoken.go ├── LICENSE ├── tags_urlfor.go └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | beego-pongo2 2 | ============ 3 | 4 | A tiny little helper for using Pongo2 with Beego. 5 | 6 | Documentation: http://godoc.org/github.com/oal/beego-pongo2 7 | 8 | ## Usage 9 | 10 | ```go 11 | package controllers 12 | 13 | import ( 14 | "github.com/astaxie/beego" 15 | "github.com/oal/beego-pongo2" 16 | ) 17 | 18 | type MainController struct { 19 | beego.Controller 20 | } 21 | 22 | func (this *MainController) Get() { 23 | pongo2.Render(this.Ctx, "page.html", pongo2.Context{ 24 | "ints": []int{1, 2, 3, 4, 5}, 25 | }) 26 | } 27 | ``` -------------------------------------------------------------------------------- /tags_xsrftoken.go: -------------------------------------------------------------------------------- 1 | package pongo2 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/astaxie/beego" 7 | p2 "gopkg.in/flosch/pongo2.v3" 8 | ) 9 | 10 | var xsrfTemplate = p2.Must(p2.FromString(``)) 11 | 12 | type tagXSRFTokenNode struct{} 13 | 14 | func (node *tagXSRFTokenNode) Execute(ctx *p2.ExecutionContext, buffer *bytes.Buffer) *p2.Error { 15 | if !beego.BConfig.WebConfig.EnableXSRF { 16 | return nil 17 | } 18 | 19 | xsrftoken := ctx.Public["_xsrf"] 20 | err := xsrfTemplate.ExecuteWriter(p2.Context{"_xsrf": xsrftoken}, buffer) 21 | if err != nil { 22 | return err.(*p2.Error) 23 | } 24 | return nil 25 | } 26 | 27 | // tagXSRFParser implements a {% xsrftoken %} tag that inserts 28 | // just like Django's {% csrftoken %}. Note that we follow Beego's convention by using "XSRF" and not "CSRF". 29 | func tagXSRFParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, *p2.Error) { 30 | return &tagXSRFTokenNode{}, nil 31 | } 32 | 33 | func init() { 34 | p2.RegisterTag("xsrftoken", tagXSRFParser) 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Olav Lindekleiv 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /tags_urlfor.go: -------------------------------------------------------------------------------- 1 | package pongo2 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/astaxie/beego" 7 | p2 "gopkg.in/flosch/pongo2.v3" 8 | ) 9 | 10 | type tagURLForNode struct { 11 | objectEvaluators []p2.IEvaluator 12 | } 13 | 14 | func (node *tagURLForNode) Execute(ctx *p2.ExecutionContext, buffer *bytes.Buffer) *p2.Error { 15 | args := make([]string, len(node.objectEvaluators)) 16 | for i, ev := range node.objectEvaluators { 17 | obj, err := ev.Evaluate(ctx) 18 | if err != nil { 19 | return err 20 | } 21 | args[i] = obj.String() 22 | } 23 | 24 | params := make([]interface{}, len(args)-1) 25 | for i := range params { 26 | params[i] = args[i+1] 27 | } 28 | 29 | url := beego.URLFor(args[0], params...) 30 | 31 | buffer.WriteString(url) 32 | return nil 33 | } 34 | 35 | // tagURLForParser implements a {% urlfor %} tag. 36 | // 37 | // urlfor takes one argument for the controller, as well as any number of key/value pairs for additional URL data. 38 | // Example: {% urlfor "UserController.View" ":slug" "oal" %} 39 | func tagURLForParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, *p2.Error) { 40 | evals := []p2.IEvaluator{} 41 | for arguments.Remaining() > 0 { 42 | expr, err := arguments.ParseExpression() 43 | evals = append(evals, expr) 44 | if err != nil { 45 | return nil, err 46 | } 47 | } 48 | 49 | if (len(evals)-1)%2 != 0 { 50 | return nil, arguments.Error("URL takes one argument for the controller and any number of optional pairs of key/value pairs.", nil) 51 | } 52 | 53 | return &tagURLForNode{evals}, nil 54 | } 55 | 56 | func init() { 57 | p2.RegisterTag("urlfor", tagURLForParser) 58 | } 59 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // A small library that lets you use Pongo2 with Beego 2 | // 3 | // When Render is called, it will populate the render context with Beego's flash messages. 4 | // You can also use {% urlfor "MyController.Action" ":key" "value" %} in your templates, and 5 | // it'll work just like `urlfor` would with `html/template`. It takes one controller argument and 6 | // zero or more key/value pairs to fill the URL. 7 | // 8 | package pongo2 9 | 10 | import ( 11 | "net/url" 12 | "strings" 13 | "sync" 14 | 15 | "github.com/astaxie/beego" 16 | "github.com/astaxie/beego/context" 17 | p2 "gopkg.in/flosch/pongo2.v3" 18 | ) 19 | 20 | type Context map[string]interface{} 21 | 22 | var templates = map[string]*p2.Template{} 23 | var mutex = &sync.RWMutex{} 24 | 25 | var devMode bool 26 | 27 | // Render takes a Beego context, template name and a Context (map[string]interface{}). 28 | // The template is parsed and cached, and gets executed into beegoCtx's ResponseWriter. 29 | // 30 | // Templates are looked up in `templates/` instead of Beego's default `views/` so that 31 | // Beego doesn't attempt to load and parse our templates with `html/template`. 32 | func Render(beegoCtx *context.Context, tmpl string, ctx Context) { 33 | mutex.RLock() 34 | template, ok := templates[tmpl] 35 | mutex.RUnlock() 36 | 37 | if !ok || devMode { 38 | var err error 39 | template, err = p2.FromFile(beego.BConfig.WebConfig.ViewsPath + "/" + tmpl) 40 | if err != nil { 41 | panic(err) 42 | } 43 | mutex.Lock() 44 | templates[tmpl] = template 45 | mutex.Unlock() 46 | } 47 | 48 | var pCtx p2.Context 49 | if ctx == nil { 50 | pCtx = p2.Context{} 51 | } else { 52 | pCtx = p2.Context(ctx) 53 | } 54 | 55 | if xsrf, ok := beegoCtx.GetSecureCookie(beego.BConfig.WebConfig.XSRFKey, "_xsrf"); ok { 56 | pCtx["_xsrf"] = xsrf 57 | } 58 | 59 | // Only override "flash" if it hasn't already been set in Context 60 | if _, ok := ctx["flash"]; !ok { 61 | if ctx == nil { 62 | ctx = Context{} 63 | } 64 | ctx["flash"] = readFlash(beegoCtx) 65 | } 66 | 67 | err := template.ExecuteWriter(pCtx, beegoCtx.ResponseWriter) 68 | if err != nil { 69 | panic(err) 70 | } 71 | } 72 | 73 | // readFlash is similar to beego.ReadFromRequest except that it takes a *context.Context instead 74 | // of a *beego.Controller, and returns a map[string]string directly instead of a Beego.FlashData 75 | // (which only has a Data field anyway). 76 | func readFlash(ctx *context.Context) map[string]string { 77 | data := map[string]string{} 78 | if cookie, err := ctx.Request.Cookie(beego.BConfig.WebConfig.FlashName); err == nil { 79 | v, _ := url.QueryUnescape(cookie.Value) 80 | vals := strings.Split(v, "\x00") 81 | for _, v := range vals { 82 | if len(v) > 0 { 83 | kv := strings.Split(v, "\x23"+beego.BConfig.WebConfig.FlashSeparator+"\x23") 84 | if len(kv) == 2 { 85 | data[kv[0]] = kv[1] 86 | } 87 | } 88 | } 89 | // read one time then delete it 90 | ctx.SetCookie(beego.BConfig.WebConfig.FlashName, "", -1, "/") 91 | } 92 | return data 93 | } 94 | 95 | func init() { 96 | devMode = beego.AppConfig.String("runmode") == "dev" 97 | beego.BConfig.WebConfig.AutoRender = false 98 | } 99 | --------------------------------------------------------------------------------