go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/frontend/main.go (about) 1 // Copyright 2022 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "context" 19 "net/http" 20 "os" 21 22 "go.chromium.org/luci/auth/identity" 23 "go.chromium.org/luci/server" 24 "go.chromium.org/luci/server/auth" 25 "go.chromium.org/luci/server/router" 26 "go.chromium.org/luci/server/templates" 27 28 "go.chromium.org/luci/analysis/frontend/handlers" 29 "go.chromium.org/luci/analysis/internal/config" 30 analysisserver "go.chromium.org/luci/analysis/server" 31 32 _ "go.chromium.org/luci/server/encryptedcookies/session/datastore" 33 ) 34 35 // prepareTemplates configures templates.Bundle used by all UI handlers. 36 func prepareTemplates(opts *server.Options) *templates.Bundle { 37 return &templates.Bundle{ 38 Loader: templates.FileSystemLoader(os.DirFS("templates")), 39 // Controls whether templates are cached. 40 DebugMode: func(context.Context) bool { return !opts.Prod }, 41 DefaultArgs: func(ctx context.Context, e *templates.Extra) (templates.Args, error) { 42 // Login and Logout URLs take a ?r query parameter to specify 43 // the redirection target after login/logout completes. 44 logoutURL, err := auth.LogoutURL(ctx, "/") 45 if err != nil { 46 return nil, err 47 } 48 loginURL, err := auth.LoginURL(ctx, "/") 49 if err != nil { 50 return nil, err 51 } 52 53 config, err := config.Get(ctx) 54 if err != nil { 55 return nil, err 56 } 57 58 return templates.Args{ 59 "MonorailHostname": config.MonorailHostname, 60 "IsAnonymous": auth.CurrentUser(ctx).Identity.Kind() == identity.Anonymous, 61 "UserName": auth.CurrentUser(ctx).Name, 62 "UserEmail": auth.CurrentUser(ctx).Email, 63 "UserAvatar": auth.CurrentUser(ctx).Picture, 64 "LogoutURL": logoutURL, 65 "LoginURL": loginURL, 66 "IsPolicyBasedBugManagementEnabled": config.BugManagement.GetPolicyBasedManagementEnabled(), 67 }, nil 68 }, 69 } 70 } 71 72 func pageBase(srv *server.Server) router.MiddlewareChain { 73 return router.NewMiddlewareChain( 74 auth.Authenticate(srv.CookieAuth), 75 templates.WithTemplates(prepareTemplates(&srv.Options)), 76 ) 77 } 78 79 // Entrypoint for the default service. 80 func main() { 81 analysisserver.Main(func(srv *server.Server) error { 82 // Only the frontend service serves frontend UI. This is because 83 // the frontend relies upon other assets (javascript, files) and 84 // it is annoying to deploy them with every backend service. 85 mw := pageBase(srv) 86 handlers := handlers.NewHandlers() 87 handlers.RegisterRoutes(srv.Routes, mw) 88 srv.Routes.Static("/static/", mw, http.Dir("./ui/dist")) 89 // Anything that is not found, serve app html and let the client side router handle it. 90 srv.Routes.NotFound(mw, handlers.IndexPage) 91 92 return nil 93 }) 94 }