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  }