Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Side by Side Diff: appengine/cmd/milo/settings/themes.go

Issue 2043423004: Make HTTP middleware easier to use (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Update tests Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698