Settings.hs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. {-# LANGUAGE CPP #-}
  2. {-# LANGUAGE NoImplicitPrelude #-}
  3. {-# LANGUAGE OverloadedStrings #-}
  4. {-# LANGUAGE RecordWildCards #-}
  5. {-# LANGUAGE TemplateHaskell #-}
  6. -- | Settings are centralized, as much as possible, into this file. This
  7. -- includes database connection settings, static file locations, etc.
  8. -- In addition, you can configure a number of different aspects of Yesod
  9. -- by overriding methods in the Yesod typeclass. That instance is
  10. -- declared in the Foundation.hs file.
  11. module Settings where
  12. import ClassyPrelude.Yesod
  13. import qualified Control.Exception as Exception
  14. import Data.Aeson (Result (..), fromJSON, withObject,
  15. (.!=), (.:?))
  16. import Data.FileEmbed (embedFile)
  17. import Data.Yaml (decodeEither')
  18. import Database.Persist.Postgresql (PostgresConf)
  19. import Language.Haskell.TH.Syntax (Exp, Name, Q)
  20. import Network.Wai.Handler.Warp (HostPreference)
  21. import Yesod.Default.Config2 (applyEnvValue, configSettingsYml)
  22. import Yesod.Default.Util (WidgetFileSettings,
  23. widgetFileNoReload,
  24. widgetFileReload)
  25. -- | Runtime settings to configure this application. These settings can be
  26. -- loaded from various sources: defaults, environment variables, config files,
  27. -- theoretically even a database.
  28. data AppSettings = AppSettings
  29. { appStaticDir :: String
  30. -- ^ Directory from which to serve static files.
  31. , appDatabaseConf :: PostgresConf
  32. -- ^ Configuration settings for accessing the database.
  33. , appRoot :: Maybe Text
  34. -- ^ Base for all generated URLs. If @Nothing@, determined
  35. -- from the request headers.
  36. , appHost :: HostPreference
  37. -- ^ Host/interface the server should bind to.
  38. , appPort :: Int
  39. -- ^ Port to listen on
  40. , appIpFromHeader :: Bool
  41. -- ^ Get the IP address from the header when logging. Useful when sitting
  42. -- behind a reverse proxy.
  43. , appDetailedRequestLogging :: Bool
  44. -- ^ Use detailed request logging system
  45. , appShouldLogAll :: Bool
  46. -- ^ Should all log messages be displayed?
  47. , appReloadTemplates :: Bool
  48. -- ^ Use the reload version of templates
  49. , appMutableStatic :: Bool
  50. -- ^ Assume that files in the static dir may change after compilation
  51. , appSkipCombining :: Bool
  52. -- ^ Perform no stylesheet/script combining
  53. -- Example app-specific configuration values.
  54. , appCopyright :: Text
  55. -- ^ Copyright text to appear in the footer of the page
  56. , appAnalytics :: Maybe Text
  57. -- ^ Google Analytics code
  58. , appAuthDummyLogin :: Bool
  59. -- ^ Indicate if auth dummy login should be enabled.
  60. }
  61. instance FromJSON AppSettings where
  62. parseJSON = withObject "AppSettings" $ \o -> do
  63. let defaultDev =
  64. #ifdef DEVELOPMENT
  65. True
  66. #else
  67. False
  68. #endif
  69. appStaticDir <- o .: "static-dir"
  70. appDatabaseConf <- o .: "database"
  71. appRoot <- o .:? "approot"
  72. appHost <- fromString <$> o .: "host"
  73. appPort <- o .: "port"
  74. appIpFromHeader <- o .: "ip-from-header"
  75. dev <- o .:? "development" .!= defaultDev
  76. appDetailedRequestLogging <- o .:? "detailed-logging" .!= dev
  77. appShouldLogAll <- o .:? "should-log-all" .!= dev
  78. appReloadTemplates <- o .:? "reload-templates" .!= dev
  79. appMutableStatic <- o .:? "mutable-static" .!= dev
  80. appSkipCombining <- o .:? "skip-combining" .!= dev
  81. appCopyright <- o .: "copyright"
  82. appAnalytics <- o .:? "analytics"
  83. appAuthDummyLogin <- o .:? "auth-dummy-login" .!= dev
  84. return AppSettings {..}
  85. -- | Settings for 'widgetFile', such as which template languages to support and
  86. -- default Hamlet settings.
  87. --
  88. -- For more information on modifying behavior, see:
  89. --
  90. -- https://github.com/yesodweb/yesod/wiki/Overriding-widgetFile
  91. widgetFileSettings :: WidgetFileSettings
  92. widgetFileSettings = def
  93. -- | How static files should be combined.
  94. combineSettings :: CombineSettings
  95. combineSettings = def
  96. -- The rest of this file contains settings which rarely need changing by a
  97. -- user.
  98. widgetFile :: String -> Q Exp
  99. widgetFile = (if appReloadTemplates compileTimeAppSettings
  100. then widgetFileReload
  101. else widgetFileNoReload)
  102. widgetFileSettings
  103. -- | Raw bytes at compile time of @config/settings.yml@
  104. configSettingsYmlBS :: ByteString
  105. configSettingsYmlBS = $(embedFile configSettingsYml)
  106. -- | @config/settings.yml@, parsed to a @Value@.
  107. configSettingsYmlValue :: Value
  108. configSettingsYmlValue = either Exception.throw id
  109. $ decodeEither' configSettingsYmlBS
  110. -- | A version of @AppSettings@ parsed at compile time from @config/settings.yml@.
  111. compileTimeAppSettings :: AppSettings
  112. compileTimeAppSettings =
  113. case fromJSON $ applyEnvValue False mempty configSettingsYmlValue of
  114. Error e -> error e
  115. Success settings -> settings
  116. -- The following two functions can be used to combine multiple CSS or JS files
  117. -- at compile time to decrease the number of http requests.
  118. -- Sample usage (inside a Widget):
  119. --
  120. -- > $(combineStylesheets 'StaticR [style1_css, style2_css])
  121. combineStylesheets :: Name -> [Route Static] -> Q Exp
  122. combineStylesheets = combineStylesheets'
  123. (appSkipCombining compileTimeAppSettings)
  124. combineSettings
  125. combineScripts :: Name -> [Route Static] -> Q Exp
  126. combineScripts = combineScripts'
  127. (appSkipCombining compileTimeAppSettings)
  128. combineSettings