github.com/saadullahsaeed/fragmenta-cms@v1.5.4/src/app/app.go (about) 1 package app 2 3 import ( 4 "os" 5 "path/filepath" 6 "strings" 7 "time" 8 9 "github.com/fragmenta/assets" 10 "github.com/fragmenta/query" 11 "github.com/fragmenta/server/config" 12 "github.com/fragmenta/server/log" 13 "github.com/fragmenta/view" 14 15 "github.com/fragmenta/fragmenta-cms/src/lib/mail" 16 "github.com/fragmenta/fragmenta-cms/src/lib/mail/adapters/sendgrid" 17 ) 18 19 // appAssets is a pkg global used in our default handlers to serve asset files. 20 var appAssets *assets.Collection 21 22 // Setup sets up our application. 23 func Setup() { 24 25 // Setup log 26 err := SetupLog() 27 if err != nil { 28 println("failed to set up logs %s", err) 29 os.Exit(1) 30 } 31 32 // Log server startup 33 msg := "Starting server" 34 if config.Production() { 35 msg = msg + " in production" 36 } 37 38 log.Info(log.Values{"msg": msg, "port": config.Get("port")}) 39 defer log.Time(time.Now(), log.Values{"msg": "Finished loading server"}) 40 41 // Set up our mail adapter 42 SetupMail() 43 44 // Set up our assets 45 SetupAssets() 46 47 // Setup our view templates 48 SetupView() 49 50 // Setup our database 51 SetupDatabase() 52 53 // Set up auth pkg and authorisation for access 54 SetupAuth() 55 56 // Set up our app routes 57 SetupRoutes() 58 59 } 60 61 // SetupDatabase sets up the db with query given our server config. 62 func SetupDatabase() { 63 defer log.Time(time.Now(), log.V{"msg": "Finished opening database", "db": config.Get("db"), "user": config.Get("db_user")}) 64 65 options := map[string]string{ 66 "adapter": config.Get("db_adapter"), 67 "user": config.Get("db_user"), 68 "password": config.Get("db_pass"), 69 "db": config.Get("db"), 70 } 71 72 // Optionally Support remote databases 73 if len(config.Get("db_host")) > 0 { 74 options["host"] = config.Get("db_host") 75 } 76 if len(config.Get("db_port")) > 0 { 77 options["port"] = config.Get("db_port") 78 } 79 if len(config.Get("db_params")) > 0 { 80 options["params"] = config.Get("db_params") 81 } 82 83 // Ask query to open the database 84 err := query.OpenDatabase(options) 85 86 if err != nil { 87 log.Fatal(log.V{"msg": "unable to read database", "db": config.Get("db"), "error": err}) 88 os.Exit(1) 89 } 90 91 } 92 93 // SetupLog sets up logging 94 func SetupLog() error { 95 96 // Set up a stderr logger with time prefix 97 logger, err := log.NewStdErr(log.PrefixDateTime) 98 if err != nil { 99 return err 100 } 101 log.Add(logger) 102 103 // Set up a file logger pointing at the right location for this config. 104 fileLog, err := log.NewFile(config.Get("log")) 105 if err != nil { 106 return err 107 } 108 log.Add(fileLog) 109 110 return nil 111 } 112 113 // SetupMail sets us up to send mail via sendgrid (requires key). 114 func SetupMail() { 115 mail.Production = config.Production() 116 mail.Service = sendgrid.New(config.Get("mail_from"), config.Get("mail_secret")) 117 } 118 119 // SetupAssets compiles or copies our assets from src into the public assets folder. 120 func SetupAssets() { 121 defer log.Time(time.Now(), log.V{"msg": "Finished loading assets"}) 122 123 // Compilation of assets is done on deploy 124 // We just load them here 125 assetsCompiled := config.GetBool("assets_compiled") 126 127 // Init the pkg global for use in ServeAssets 128 appAssets = assets.New(assetsCompiled) 129 130 // Load assets in production, always compile if in dev 131 load := true 132 if config.Production() { 133 load = (appAssets.Load() != nil) 134 } 135 if load { 136 // Compile assets for the first time 137 log.Info(log.V{"msg": "Compiling Asssets"}) 138 139 err := appAssets.Compile("src", "public") 140 if err != nil { 141 log.Fatal(log.V{"a": "unable to compile assets", "error": err}) 142 os.Exit(1) 143 } 144 // If we have a theme, load assets from the them as well 145 if themePath() != "" { 146 err = appAssets.Compile(themePath(), "public") 147 if err != nil { 148 log.Fatal(log.V{"a": "unable to compile assets", "error": err}) 149 os.Exit(1) 150 } 151 } 152 153 } 154 155 } 156 157 // SetupView sets up the view package by loadind templates. 158 func SetupView() { 159 defer log.Time(time.Now(), log.V{"msg": "Finished loading templates"}) 160 161 view.Production = config.Production() 162 163 // Start with default source path 164 paths := []string{"src"} 165 166 // Add a theme path if we have one 167 if themePath() != "" { 168 log.Log(log.V{"msg": "loading templates for theme", "theme": config.Get("theme")}) 169 paths = append(paths, themePath()) 170 } 171 172 err := view.LoadTemplatesAtPaths(paths, helperFuncs()) 173 if err != nil { 174 log.Fatal(log.V{"msg": "unable to read templates", "error": err}) 175 os.Exit(1) 176 } 177 178 } 179 180 // helperFuncs returns a setr of helper functions for view templates 181 func helperFuncs() map[string]interface{} { 182 183 helpers := view.DefaultHelpers() 184 185 // Set up helpers which are aware of fingerprinted assets 186 // These behave differently depending on the compile flag above 187 // when compile is set to no, they use precompiled assets 188 // otherwise they serve all files in a group separately 189 helpers["style"] = appAssets.StyleLink 190 helpers["script"] = appAssets.ScriptLink 191 192 // Get the server config for the root_url 193 rootURL := config.Get("root_url") 194 195 // If running locally use localhost instead 196 host, err := os.Hostname() 197 if err == nil && strings.HasSuffix(host, ".local") { 198 rootURL = "http://localhost:3000" 199 } 200 201 helpers["root_url"] = func() string { 202 return rootURL 203 } 204 205 return helpers 206 } 207 208 // themePath returns the path to the theme src dir (if a theme is chosen) 209 func themePath() string { 210 if config.Get("theme") == "" { 211 return "" 212 } 213 return filepath.Join("themes", config.Get("theme"), "src") 214 }