Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package settings | 5 package settings |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 "io" | 9 "io" |
| 10 "net/http" | 10 "net/http" |
| 11 "path" | 11 "path" |
| 12 "sort" | 12 "sort" |
| 13 "strings" | 13 "strings" |
| 14 | 14 |
| 15 "google.golang.org/appengine" | 15 "google.golang.org/appengine" |
| 16 | 16 |
| 17 "github.com/julienschmidt/httprouter" | 17 "github.com/julienschmidt/httprouter" |
| 18 "github.com/luci/gae/service/info" | 18 "github.com/luci/gae/service/info" |
| 19 "github.com/luci/luci-go/appengine/cmd/milo/miloerror" | 19 "github.com/luci/luci-go/appengine/cmd/milo/miloerror" |
| 20 "github.com/luci/luci-go/appengine/gaeauth/server" | 20 "github.com/luci/luci-go/appengine/gaeauth/server" |
| 21 "github.com/luci/luci-go/appengine/gaemiddleware" | 21 "github.com/luci/luci-go/appengine/gaemiddleware" |
| 22 "github.com/luci/luci-go/common/clock" | 22 "github.com/luci/luci-go/common/clock" |
| 23 "github.com/luci/luci-go/server/auth" | 23 "github.com/luci/luci-go/server/auth" |
| 24 » "github.com/luci/luci-go/server/middleware" | 24 » "github.com/luci/luci-go/server/router" |
| 25 "github.com/luci/luci-go/server/templates" | 25 "github.com/luci/luci-go/server/templates" |
| 26 "golang.org/x/net/context" | 26 "golang.org/x/net/context" |
| 27 ) | 27 ) |
| 28 | 28 |
| 29 type themeContextKey string | 29 type themeContextKey string |
| 30 | 30 |
| 31 // NamedBundle is a tuple of a name (That matches it's corresponding theme) | 31 // NamedBundle is a tuple of a name (That matches it's corresponding theme) |
| 32 // and a template bundle. | 32 // and a template bundle. |
| 33 type NamedBundle struct { | 33 type NamedBundle struct { |
| 34 Name string | 34 Name string |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 return result | 112 return result |
| 113 } | 113 } |
| 114 | 114 |
| 115 // UseNamedBundle is like templates.Use, but with the choice of one of many bund les (themes) | 115 // UseNamedBundle is like templates.Use, but with the choice of one of many bund les (themes) |
| 116 func UseNamedBundle(c context.Context, nb NamedBundle) (context.Context, error) { | 116 func UseNamedBundle(c context.Context, nb NamedBundle) (context.Context, error) { |
| 117 err := nb.Bundle.EnsureLoaded(c) | 117 err := nb.Bundle.EnsureLoaded(c) |
| 118 return context.WithValue(c, themeContextKey(nb.Name), nb.Bundle), err | 118 return context.WithValue(c, themeContextKey(nb.Name), nb.Bundle), err |
| 119 } | 119 } |
| 120 | 120 |
| 121 // withNamedBundle is like templates.WithTemplates, but with the choice of one o f many bundles (themes) | 121 // withNamedBundle is like templates.WithTemplates, but with the choice of one o f many bundles (themes) |
| 122 func withNamedBundle(h middleware.Handler, nb NamedBundle) middleware.Handler { | 122 func withNamedBundle(nb NamedBundle) router.Handler { |
| 123 » return func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params) { | 123 » return func(c *router.Context) { |
| 124 » » c, err := UseNamedBundle(c, nb) // calls EnsureLoaded and initia lizes b.err inside | 124 » » var err error |
| 125 » » c.Context, err = UseNamedBundle(c.Context, nb) // calls EnsureLo aded and initializes b.err inside | |
| 125 if err != nil { | 126 if err != nil { |
| 126 » » » http.Error(rw, fmt.Sprintf("Can't load HTML templates.\n %s", err), http.StatusInternalServerError) | 127 » » » http.Error(c.Writer, fmt.Sprintf("Can't load HTML templa tes.\n%s", err), http.StatusInternalServerError) |
| 127 » » » return | 128 » » » c.Abort() |
| 128 } | 129 } |
| 129 h(c, rw, r, p) | |
| 130 } | 130 } |
| 131 } | 131 } |
| 132 | 132 |
| 133 // themedMustRender renders theme and panics if it can't be rendered. This shou ld never fail in | 133 // themedMustRender renders theme and panics if it can't be rendered. This shou ld never fail in |
| 134 // production. | 134 // production. |
| 135 func themedMustRender(c context.Context, out io.Writer, theme, name string, args templates.Args) { | 135 func themedMustRender(c context.Context, out io.Writer, theme, name string, args templates.Args) { |
| 136 if b, _ := c.Value(themeContextKey(theme)).(*templates.Bundle); b != nil { | 136 if b, _ := c.Value(themeContextKey(theme)).(*templates.Bundle); b != nil { |
| 137 blob, err := b.Render(c, name, args) | 137 blob, err := b.Render(c, name, args) |
| 138 if err != nil { | 138 if err != nil { |
| 139 panic(fmt.Errorf("Could not render template %s from them e %s:\n%s", name, theme, err)) | 139 panic(fmt.Errorf("Could not render template %s from them e %s:\n%s", name, theme, err)) |
| 140 } | 140 } |
| 141 _, err = out.Write(blob) | 141 _, err = out.Write(blob) |
| 142 if err != nil { | 142 if err != nil { |
| 143 panic(fmt.Errorf("Could not write out template %s from t heme %s:\n%s", name, theme, err)) | 143 panic(fmt.Errorf("Could not write out template %s from t heme %s:\n%s", name, theme, err)) |
| 144 } | 144 } |
| 145 return | 145 return |
| 146 } | 146 } |
| 147 panic(fmt.Errorf("Error: Could not load template %s from theme %s", name , theme)) | 147 panic(fmt.Errorf("Error: Could not load template %s from theme %s", name , theme)) |
| 148 } | 148 } |
| 149 | 149 |
| 150 // Base adds the basic luci appengine middlewares. | 150 // Base adds the basic luci appengine middlewares. |
| 151 func Base(h middleware.Handler) httprouter.Handle { | 151 func Base() []router.Handler { |
| 152 » // TODO(nishanths): Allocate h for total length instead of repeated appe nd() | |
| 153 » // in loop. | |
| 152 methods := auth.Authenticator{ | 154 methods := auth.Authenticator{ |
| 153 &server.OAuth2Method{Scopes: []string{server.EmailScope}}, | 155 &server.OAuth2Method{Scopes: []string{server.EmailScope}}, |
| 154 server.CookieAuth, | 156 server.CookieAuth, |
| 155 &server.InboundAppIDAuthMethod{}, | 157 &server.InboundAppIDAuthMethod{}, |
| 156 } | 158 } |
| 159 h := append(gaemiddleware.BaseProd(), auth.Use(methods)) | |
| 157 for _, nb := range GetTemplateBundles() { | 160 for _, nb := range GetTemplateBundles() { |
| 158 » » h = withNamedBundle(h, nb) | 161 » » h = append(h, withNamedBundle(nb)) |
| 159 } | 162 } |
| 160 » return gaemiddleware.BaseProd(auth.Use(h, methods)) | 163 » return h |
| 161 } | 164 } |
| 162 | 165 |
| 163 // Wrap wraps Milo "Render" functions and emits a middleware.Handler function. Of note | 166 // Wrap wraps Milo "Render" functions and emits a middleware.Handler function. Of note |
| 164 // is that Render functions' interface into rendering is purely through a single | 167 // is that Render functions' interface into rendering is purely through a single |
| 165 // templates.Args value which gets rendered here, while the http.ResponseWriter | 168 // templates.Args value which gets rendered here, while the http.ResponseWriter |
| 166 // is stripped out. | 169 // is stripped out. |
| 167 func Wrap(h ThemedHandler) func(http.ResponseWriter, *http.Request, httprouter.P arams) { | 170 func Wrap(h ThemedHandler) router.Handler { |
| 168 » hx := func(c context.Context, w http.ResponseWriter, r *http.Request, p httprouter.Params) { | 171 » return func(c *router.Context) { |
| 169 // Figure out if we need to do the things. | 172 // Figure out if we need to do the things. |
| 170 » » theme := GetTheme(c, r) | 173 » » theme := GetTheme(c.Context, c.Request) |
| 171 template := h.GetTemplateName(theme) | 174 template := h.GetTemplateName(theme) |
| 172 | 175 |
| 173 // Do the things. | 176 // Do the things. |
| 174 » » args, err := h.Render(c, r, p) | 177 » » args, err := h.Render(c.Context, c.Request, c.Params) |
| 175 | 178 |
| 176 // Throw errors. | 179 // Throw errors. |
| 177 // TODO(hinoka): Add themes and templates for errors so they loo k better. | 180 // TODO(hinoka): Add themes and templates for errors so they loo k better. |
| 178 if err != nil { | 181 if err != nil { |
| 179 if merr, ok := err.(*miloerror.Error); ok { | 182 if merr, ok := err.(*miloerror.Error); ok { |
| 180 » » » » http.Error(w, merr.Message, merr.Code) | 183 » » » » http.Error(c.Writer, merr.Message, merr.Code) |
| 181 } else { | 184 } else { |
| 182 » » » » http.Error(w, err.Error(), http.StatusInternalSe rverError) | 185 » » » » http.Error(c.Writer, err.Error(), http.StatusInt ernalServerError) |
| 183 } | 186 } |
| 187 c.Abort() | |
| 184 return | 188 return |
| 185 } | 189 } |
| 186 | 190 |
| 187 // Render the stuff. | 191 // Render the stuff. |
| 188 name := fmt.Sprintf("pages/%s", template) | 192 name := fmt.Sprintf("pages/%s", template) |
| 189 » » themedMustRender(c, w, theme.Name, name, *args) | 193 » » themedMustRender(c.Context, c.Writer, theme.Name, name, *args) |
| 190 } | 194 } |
| 191 return Base(hx) | |
|
hinoka
2016/06/13 18:31:20
Don't we still need to install the base middleware
nishanths
2016/06/15 18:25:08
You're right. :) But they were now being added at
| |
| 192 } | 195 } |
| OLD | NEW |