mirror of
https://github.com/simonmichael/hledger.git
synced 2024-12-26 03:42:25 +03:00
web: more yesod 0.8 migration; adopt the scaffolding app's layout, slightly simplified
This commit is contained in:
parent
274d072c4d
commit
dc6c3dec76
@ -1,47 +0,0 @@
|
||||
%script!type=text/javascript
|
||||
$$(document).ready(function() {
|
||||
/* dhtmlxcombo setup */
|
||||
window.dhx_globalImgPath="../static/";
|
||||
var desccombo = new dhtmlXCombo("description");
|
||||
var acct1combo = new dhtmlXCombo("account1");
|
||||
var acct2combo = new dhtmlXCombo("account2");
|
||||
desccombo.enableFilteringMode(true);
|
||||
acct1combo.enableFilteringMode(true);
|
||||
acct2combo.enableFilteringMode(true);
|
||||
desccombo.setSize(300);
|
||||
acct1combo.setSize(300);
|
||||
acct2combo.setSize(300);
|
||||
});
|
||||
|
||||
%form#addform!method=POST;
|
||||
%table.form
|
||||
%tr
|
||||
%td!colspan=4
|
||||
%table
|
||||
%tr#descriptionrow
|
||||
%td
|
||||
Date:
|
||||
%td
|
||||
%input.textinput!size=15!name=date!value=$date$
|
||||
%td!style=padding-left:1em;
|
||||
Description:
|
||||
%td
|
||||
%select!id=description!name=description
|
||||
%option
|
||||
$forall descriptions d
|
||||
%option!value=$d$ $d$
|
||||
%tr.helprow
|
||||
%td
|
||||
%td
|
||||
.help $datehelp$ $
|
||||
%td
|
||||
%td
|
||||
.help $deschelp$
|
||||
$postingfields1$
|
||||
$postingfields2$
|
||||
%tr#addbuttonrow
|
||||
%td!colspan=4
|
||||
%input!type=hidden!name=action!value=add
|
||||
%input!type=submit!name=submit!value="add transaction"
|
||||
$if manyfiles
|
||||
\ to: ^journalselect.files^
|
@ -1,15 +0,0 @@
|
||||
%tr#postingrow
|
||||
%td!align=right $acctlabel$:
|
||||
%td
|
||||
%select!id=$acctvar$!name=$acctvar$
|
||||
%option
|
||||
$forall acctnames a
|
||||
%option!value=$a$ $a$
|
||||
$amtfield$
|
||||
%tr.helprow
|
||||
%td
|
||||
%td
|
||||
.help $accthelp$
|
||||
%td
|
||||
%td
|
||||
.help $amthelp$
|
@ -1,9 +0,0 @@
|
||||
!!!
|
||||
%html
|
||||
%head
|
||||
%title $pageTitle.pc$
|
||||
^pageHead.pc^
|
||||
%body
|
||||
$maybe mmsg msg
|
||||
#message $msg$
|
||||
^pageBody.pc^
|
@ -1,6 +0,0 @@
|
||||
body
|
||||
font-family: sans-serif
|
||||
h1
|
||||
text-align: center
|
||||
h2#$h2id$
|
||||
color: red
|
@ -1,12 +0,0 @@
|
||||
%h1 Hello
|
||||
%h2#$h2id$ You do not have Javascript enabled.
|
||||
$maybe mu u
|
||||
%p
|
||||
You are logged in as $userIdent.snd.u$. $
|
||||
%a!href=@AuthR.LogoutR@ Logout
|
||||
\.
|
||||
$nothing
|
||||
%p
|
||||
You are not logged in. $
|
||||
%a!href=@AuthR.LoginR@ Login now
|
||||
\.
|
@ -1,3 +0,0 @@
|
||||
window.onload = function(){
|
||||
document.getElementById("%h2id%").innerHTML = "<i>Added from JavaScript.</i>";
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 309 B After Width: | Height: | Size: 309 B |
BIN
hledger-web/.hledger/web/static/favicon.ico
Normal file
BIN
hledger-web/.hledger/web/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -1,3 +1,10 @@
|
||||
/* LOCAL:
|
||||
hledger-web executables built in this repo will include these local styles
|
||||
when generating the web support files
|
||||
*/
|
||||
body { border-top: thin solid red; }
|
||||
/* END LOCAL */
|
||||
|
||||
/* hledger web ui styles */
|
||||
|
||||
/*------------------------------------------------------------------------------------------*/
|
9
hledger-web/.hledger/web/templates/default-layout.hamlet
Normal file
9
hledger-web/.hledger/web/templates/default-layout.hamlet
Normal file
@ -0,0 +1,9 @@
|
||||
!!!
|
||||
<html
|
||||
<head
|
||||
<title>#{pageTitle pc}
|
||||
^{pageHead pc}
|
||||
<body
|
||||
$maybe msg <- mmsg
|
||||
<div #message>#{msg}
|
||||
^{pageBody pc}
|
4
hledger-web/.hledger/web/templates/homepage.cassius
Normal file
4
hledger-web/.hledger/web/templates/homepage.cassius
Normal file
@ -0,0 +1,4 @@
|
||||
h1
|
||||
text-align: center
|
||||
h2##{h2id}
|
||||
color: #990
|
2
hledger-web/.hledger/web/templates/homepage.hamlet
Normal file
2
hledger-web/.hledger/web/templates/homepage.hamlet
Normal file
@ -0,0 +1,2 @@
|
||||
<h1>Hello
|
||||
<h2 ##{h2id}>You could have Javascript enabled.
|
3
hledger-web/.hledger/web/templates/homepage.julius
Normal file
3
hledger-web/.hledger/web/templates/homepage.julius
Normal file
@ -0,0 +1,3 @@
|
||||
window.onload = function(){
|
||||
document.getElementById("#{h2id}").innerHTML = "<i>Added from JavaScript.</i>";
|
||||
}
|
100
hledger-web/App.hs
Normal file
100
hledger-web/App.hs
Normal file
@ -0,0 +1,100 @@
|
||||
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module App
|
||||
( App (..)
|
||||
, AppRoute (..)
|
||||
, resourcesApp
|
||||
, Handler
|
||||
, Widget
|
||||
, module Yesod.Core
|
||||
, module Settings
|
||||
, StaticRoute (..)
|
||||
, lift
|
||||
, liftIO
|
||||
) where
|
||||
|
||||
import Yesod.Core
|
||||
import Yesod.Helpers.Static
|
||||
import qualified Settings
|
||||
import System.Directory
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
import Settings (hamletFile, cassiusFile, juliusFile, widgetFile)
|
||||
import Control.Monad (unless)
|
||||
import Control.Monad.Trans.Class (lift)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import qualified Data.Text as T
|
||||
|
||||
import Hledger.Cli.Options (Opt)
|
||||
import Hledger.Data (Journal)
|
||||
|
||||
-- | The site argument for your application. This can be a good place to
|
||||
-- keep settings and values requiring initialization before your application
|
||||
-- starts running, such as database connections. Every handler will have
|
||||
-- access to the data present here.
|
||||
data App = App
|
||||
{getStatic :: Static -- ^ Settings for static file serving.
|
||||
,appRoot :: T.Text
|
||||
,appOpts :: [Opt]
|
||||
,appArgs :: [String]
|
||||
,appJournal :: Journal
|
||||
}
|
||||
|
||||
-- | A useful synonym; most of the handler functions in your application
|
||||
-- will need to be of this type.
|
||||
type Handler = GHandler App App
|
||||
|
||||
-- | A useful synonym; most of the widgets functions in your application
|
||||
-- will need to be of this type.
|
||||
type Widget = GWidget App App
|
||||
|
||||
-- This is where we define all of the routes in our application. For a full
|
||||
-- explanation of the syntax, please see:
|
||||
-- http://docs.yesodweb.com/book/web-routes-quasi/
|
||||
--
|
||||
-- This function does three things:
|
||||
--
|
||||
-- * Creates the route datatype AppRoute. Every valid URL in your
|
||||
-- application can be represented as a value of this type.
|
||||
-- * Creates the associated type:
|
||||
-- type instance Route App = AppRoute
|
||||
-- * Creates the value resourcesApp which contains information on the
|
||||
-- resources declared below. This is used in Controller.hs by the call to
|
||||
-- mkYesodDispatch
|
||||
--
|
||||
-- What this function does *not* do is create a YesodSite instance for
|
||||
-- App. Creating that instance requires all of the handler functions
|
||||
-- for our application to be in scope. However, the handler functions
|
||||
-- usually require access to the AppRoute datatype. Therefore, we
|
||||
-- split these actions into two functions and place them in separate files.
|
||||
mkYesodData "App" $(parseRoutesFile "routes")
|
||||
|
||||
-- Please see the documentation for the Yesod typeclass. There are a number
|
||||
-- of settings which can be configured by overriding methods here.
|
||||
instance Yesod App where
|
||||
approot = appRoot
|
||||
|
||||
defaultLayout widget = do
|
||||
mmsg <- getMessage
|
||||
pc <- widgetToPageContent $ do
|
||||
widget
|
||||
addCassius $(Settings.cassiusFile "default-layout")
|
||||
hamletToRepHtml $(Settings.hamletFile "default-layout")
|
||||
|
||||
-- This is done to provide an optimization for serving static files from
|
||||
-- a separate domain. Please see the staticroot setting in Settings.hs
|
||||
-- urlRenderOverride a (StaticR s) =
|
||||
-- Just $ uncurry (joinPath a Settings.staticroot) $ renderRoute s
|
||||
-- urlRenderOverride _ _ = Nothing
|
||||
|
||||
-- This function creates static content files in the static folder
|
||||
-- and names them based on a hash of their content. This allows
|
||||
-- expiration dates to be set far in the future without worry of
|
||||
-- users receiving stale content.
|
||||
addStaticContent ext' _ content = do
|
||||
let fn = base64md5 content ++ '.' : T.unpack ext'
|
||||
let statictmp = Settings.staticdir ++ "/tmp/"
|
||||
liftIO $ createDirectoryIfMissing True statictmp
|
||||
let fn' = statictmp ++ fn
|
||||
exists <- liftIO $ doesFileExist fn'
|
||||
unless exists $ liftIO $ L.writeFile fn' content
|
||||
return $ Just $ Right (StaticR $ StaticRoute ["tmp", T.pack fn] [], [])
|
56
hledger-web/Controller.hs
Normal file
56
hledger-web/Controller.hs
Normal file
@ -0,0 +1,56 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||
module Controller
|
||||
( withApp
|
||||
, withDevelApp
|
||||
) where
|
||||
|
||||
import App
|
||||
import Settings
|
||||
import Yesod.Helpers.Static
|
||||
import Data.ByteString (ByteString)
|
||||
import Network.Wai (Application)
|
||||
import Data.Dynamic (Dynamic, toDyn)
|
||||
import System.FilePath ((</>))
|
||||
|
||||
-- Import all relevant handler modules here.
|
||||
import Handlers
|
||||
|
||||
import Hledger.Data (nulljournal)
|
||||
|
||||
-- This line actually creates our YesodSite instance. It is the second half
|
||||
-- of the call to mkYesodData which occurs in App.hs. Please see
|
||||
-- the comments there for more details.
|
||||
mkYesodDispatch "App" resourcesApp
|
||||
|
||||
-- Some default handlers that ship with the Yesod site template. You will
|
||||
-- very rarely need to modify this.
|
||||
getFaviconR :: Handler ()
|
||||
getFaviconR = sendFile "image/x-icon" $ Settings.staticdir </> "favicon.ico"
|
||||
|
||||
getRobotsR :: Handler RepPlain
|
||||
getRobotsR = return $ RepPlain $ toContent ("User-agent: *" :: ByteString)
|
||||
|
||||
-- This function allocates resources (such as a database connection pool),
|
||||
-- performs initialization and creates a WAI application. This is also the
|
||||
-- place to put your migrate statements to have automatic database
|
||||
-- migrations handled by Yesod.
|
||||
withApp :: App -> (Application -> IO a) -> IO a
|
||||
withApp a f = do
|
||||
toWaiApp a >>= f
|
||||
-- where
|
||||
-- s = static Settings.staticdir
|
||||
|
||||
withDevelApp :: Dynamic
|
||||
-- withDevelApp = undefined
|
||||
withDevelApp = toDyn (withApp a :: (Application -> IO ()) -> IO ())
|
||||
where a = App{
|
||||
getStatic=static Settings.staticdir
|
||||
,appRoot=Settings.defapproot
|
||||
,appOpts=[]
|
||||
,appArgs=[]
|
||||
,appJournal=nulljournal
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-|
|
||||
|
||||
Support files used by the web app are embedded here at compile time via
|
||||
template haskell magic. This allows us minimise deployment hassle by
|
||||
recreating them on the filesystem when needed (since hamlet can not use
|
||||
the embedded files directly.) Installing on the filesystem has the added
|
||||
benefit of making them easily customisable.
|
||||
Support files (static files and templates) used by the web app are
|
||||
embedded in this module at compile time. Since hamlet can not use the
|
||||
embedded files directly, we also provide a way to write them out to the
|
||||
filesystem at startup, when needed. This simplifies installation for
|
||||
end-users, and customisation too.
|
||||
|
||||
-}
|
||||
module Hledger.Web.Files
|
||||
module EmbeddedFiles
|
||||
(
|
||||
files
|
||||
,createFilesIfMissing
|
||||
@ -18,9 +18,9 @@ import Control.Monad
|
||||
import qualified Data.ByteString as B
|
||||
import Data.FileEmbed (embedDir)
|
||||
import System.Directory
|
||||
import System.FilePath
|
||||
|
||||
import Hledger.Web.Settings (datadir)
|
||||
|
||||
import Settings (datadir)
|
||||
|
||||
-- | An embedded copy of all files below the the hledger-web data
|
||||
-- directory (@.hledger/web/@) at compile time, as (FilePath,ByteString)
|
||||
@ -40,5 +40,7 @@ createFilesIfMissing = do
|
||||
else do
|
||||
createDirectoryIfMissing True datadir
|
||||
setCurrentDirectory datadir
|
||||
forM_ files $ \(f,d) -> B.writeFile f d
|
||||
forM_ files $ \(f,d) -> do
|
||||
createDirectoryIfMissing True $ takeDirectory f
|
||||
B.writeFile f d
|
||||
return True
|
File diff suppressed because it is too large
Load Diff
@ -1,100 +0,0 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-|
|
||||
hledger-web - a hledger add-on providing a web interface.
|
||||
Copyright (c) 2007-2011 Simon Michael <simon@joyful.com>
|
||||
Released under GPL version 3 or later.
|
||||
-}
|
||||
|
||||
module Hledger.Web.Main where
|
||||
|
||||
import Control.Concurrent (forkIO, threadDelay)
|
||||
import Data.Text(pack)
|
||||
import System.Exit (exitFailure)
|
||||
import System.IO.Storage (withStore, putValue,)
|
||||
import System.Console.GetOpt
|
||||
import Yesod
|
||||
import Yesod.Helpers.Static
|
||||
|
||||
import Hledger.Cli.Options
|
||||
import Hledger.Cli.Utils (withJournalDo, openBrowserOn)
|
||||
import Hledger.Cli.Version (progversionstr, binaryfilename)
|
||||
import Hledger.Data
|
||||
import Prelude hiding (putStr, putStrLn)
|
||||
import Hledger.Data.UTF8 (putStr, putStrLn)
|
||||
import Hledger.Web.App (App(..))
|
||||
import Hledger.Web.Files (createFilesIfMissing)
|
||||
import Hledger.Web.Settings (browserstartdelay, defhost, defport, datadir)
|
||||
|
||||
|
||||
progname_web = progname_cli ++ "-web"
|
||||
|
||||
options_web :: [OptDescr Opt]
|
||||
options_web = [
|
||||
Option "" ["base-url"] (ReqArg BaseUrl "URL") "use this base url (default http://localhost:PORT)"
|
||||
,Option "" ["port"] (ReqArg Port "N") "serve on tcp port N (default 5000)"
|
||||
]
|
||||
|
||||
usage_preamble_web =
|
||||
"Usage: hledger-web [OPTIONS] [PATTERNS]\n" ++
|
||||
"\n" ++
|
||||
"Reads your ~/.journal file, or another specified by $LEDGER or -f, and\n" ++
|
||||
"starts a web ui server. Also attempts to start a web browser (unless --debug).\n" ++
|
||||
"\n"
|
||||
|
||||
usage_options_web = usageInfo "hledger-web options:" options_web ++ "\n"
|
||||
|
||||
usage_web = concat [
|
||||
usage_preamble_web
|
||||
,usage_options_web
|
||||
,usage_options_cli
|
||||
,usage_postscript_cli
|
||||
]
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
(opts, args) <- parseArgumentsWith $ options_cli++options_web
|
||||
run opts args
|
||||
where
|
||||
run opts args
|
||||
| Help `elem` opts = putStr usage_web
|
||||
| Version `elem` opts = putStrLn $ progversionstr progname_web
|
||||
| BinaryFilename `elem` opts = putStrLn $ binaryfilename progname_web
|
||||
| otherwise = withJournalDo opts args "web" web
|
||||
|
||||
-- | The web command.
|
||||
web :: [Opt] -> [String] -> Journal -> IO ()
|
||||
web opts args j = do
|
||||
created <- createFilesIfMissing
|
||||
if created
|
||||
then do
|
||||
putStrLn $ "Installing support files in "++datadir++" - done, please run again."
|
||||
exitFailure
|
||||
else do
|
||||
putStrLn $ "Using support files in "++datadir
|
||||
let host = defhost
|
||||
port = fromMaybe defport $ portFromOpts opts
|
||||
baseurl = fromMaybe (printf "http://%s:%d" host port) $ baseUrlFromOpts opts
|
||||
unless (Debug `elem` opts) $ forkIO (browser baseurl) >> return ()
|
||||
server baseurl port opts args j
|
||||
|
||||
server :: String -> Int -> [Opt] -> [String] -> Journal -> IO ()
|
||||
server baseurl port opts args j = do
|
||||
printf "Starting http server on port %d with base url %s\n" port baseurl
|
||||
withStore "hledger" $ do
|
||||
putValue "hledger" "journal" j
|
||||
warpDebug port $ App{
|
||||
-- appConnPool=Nothing
|
||||
appRoot=pack baseurl
|
||||
,appDataDir=datadir
|
||||
,appStaticSettings=static datadir
|
||||
,appOpts=opts
|
||||
,appArgs=args
|
||||
,appJournal=j
|
||||
}
|
||||
|
||||
browser :: String -> IO ()
|
||||
browser baseurl = do
|
||||
threadDelay $ fromIntegral browserstartdelay
|
||||
putStrLn "Attempting to start a web browser"
|
||||
openBrowserOn baseurl >> return ()
|
||||
|
@ -1,128 +0,0 @@
|
||||
{-# LANGUAGE CPP, OverloadedStrings #-}
|
||||
module Hledger.Web.Settings
|
||||
(
|
||||
hamletFile
|
||||
, cassiusFile
|
||||
, juliusFile
|
||||
-- , connStr
|
||||
-- , ConnectionPool
|
||||
-- , withConnectionPool
|
||||
-- , runConnectionPool
|
||||
, approot
|
||||
, staticroot
|
||||
, datadir
|
||||
, defhost
|
||||
, defport
|
||||
, browserstartdelay
|
||||
, hledgerorgurl
|
||||
, manualurl
|
||||
, style_css
|
||||
, hledger_js
|
||||
, jquery_js
|
||||
, jquery_url_js
|
||||
, dhtmlxcommon_js
|
||||
, dhtmlxcombo_js
|
||||
, robots_txt
|
||||
) where
|
||||
|
||||
import Language.Haskell.TH.Syntax
|
||||
import System.FilePath ((</>))
|
||||
import qualified Text.Cassius as H
|
||||
import qualified Text.Hamlet as H
|
||||
import qualified Text.Julius as H
|
||||
import Text.Printf (printf)
|
||||
-- import Database.Persist.Sqlite
|
||||
-- import Yesod (MonadCatchIO)
|
||||
import Yesod.Helpers.Static
|
||||
|
||||
|
||||
browserstartdelay = 100000 -- microseconds
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- urls
|
||||
----------------------------------------------------------------------
|
||||
|
||||
hledgerorgurl, manualurl :: String
|
||||
hledgerorgurl = "http://hledger.org"
|
||||
manualurl = hledgerorgurl++"/MANUAL.html"
|
||||
|
||||
defhost = "localhost" :: String
|
||||
defport = 5000
|
||||
|
||||
approot :: String
|
||||
#ifdef PRODUCTION
|
||||
approot = printf "http://%s:%d" defhost (defport :: Int) :: String
|
||||
#else
|
||||
approot = printf "http://%s:%d" defhost (defport :: Int) :: String
|
||||
#endif
|
||||
|
||||
staticroot :: String
|
||||
staticroot = approot ++ "/static"
|
||||
|
||||
-- Some static routes we can refer to by name, without hard-coded filesystem location.
|
||||
style_css = StaticRoute ["style.css"] []
|
||||
hledger_js = StaticRoute ["hledger.js"] []
|
||||
jquery_js = StaticRoute ["jquery.js"] []
|
||||
jquery_url_js = StaticRoute ["jquery.url.js"] []
|
||||
dhtmlxcommon_js = StaticRoute ["dhtmlxcommon.js"] []
|
||||
dhtmlxcombo_js = StaticRoute ["dhtmlxcombo.js"] []
|
||||
|
||||
-- Content for /robots.txt
|
||||
robots_txt = "User-agent: *"
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- filesystem
|
||||
----------------------------------------------------------------------
|
||||
|
||||
-- | Hard-coded data directory path. This must be in your current dir when
|
||||
-- you compile. At run time it's also required but we'll auto-create it.
|
||||
datadir :: FilePath
|
||||
datadir = "./.hledger/web/"
|
||||
|
||||
-- The following are compile-time macros. If the file paths they point to
|
||||
-- don't exist, they will give an error (at compile time). If PRODUCTION
|
||||
-- is defined, files are read only once at (startup?) time, otherwise
|
||||
-- repeatedly at run time.
|
||||
|
||||
hamletFile :: FilePath -> Q Exp
|
||||
#ifdef PRODUCTION
|
||||
hamletFile x = H.hamletFile $ datadir </> (x ++ ".hamlet")
|
||||
#else
|
||||
hamletFile x = H.hamletFileDebug $ datadir </> (x ++ ".hamlet")
|
||||
#endif
|
||||
|
||||
cassiusFile :: FilePath -> Q Exp
|
||||
#ifdef PRODUCTION
|
||||
cassiusFile x = H.cassiusFile $ datadir </> (x ++ ".cassius")
|
||||
#else
|
||||
cassiusFile x = H.cassiusFileDebug $ datadir </> (x ++ ".cassius")
|
||||
#endif
|
||||
|
||||
juliusFile :: FilePath -> Q Exp
|
||||
#ifdef PRODUCTION
|
||||
juliusFile x = H.juliusFile $ datadir </> (x ++ ".julius")
|
||||
#else
|
||||
juliusFile x = H.juliusFileDebug $ datadir </> (x ++ ".julius")
|
||||
#endif
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- database
|
||||
----------------------------------------------------------------------
|
||||
|
||||
-- connStr :: String
|
||||
-- #ifdef PRODUCTION
|
||||
-- connStr = "production.db3"
|
||||
-- #else
|
||||
-- connStr = "debug.db3"
|
||||
-- #endif
|
||||
|
||||
-- connectionCount :: Int
|
||||
-- connectionCount = 10
|
||||
|
||||
-- withConnectionPool :: MonadCatchIO m => (ConnectionPool -> m a) -> m a
|
||||
-- withConnectionPool = withSqlitePool connStr connectionCount
|
||||
|
||||
-- runConnectionPool :: MonadCatchIO m => SqlPersist m a -> ConnectionPool -> m a
|
||||
-- runConnectionPool = runSqlPool
|
||||
|
147
hledger-web/Settings.hs
Normal file
147
hledger-web/Settings.hs
Normal file
@ -0,0 +1,147 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
-- | Settings are centralized, as much as possible, into this file. This
|
||||
-- includes database connection settings, static file locations, etc.
|
||||
-- In addition, you can configure a number of different aspects of Yesod
|
||||
-- by overriding methods in the Yesod typeclass. That instance is
|
||||
-- declared in the hledger-web.hs file.
|
||||
module Settings
|
||||
( hamletFile
|
||||
, cassiusFile
|
||||
, juliusFile
|
||||
, luciusFile
|
||||
, widgetFile
|
||||
, datadir
|
||||
, staticdir
|
||||
, defhost
|
||||
, defport
|
||||
, defapproot
|
||||
-- , staticroot
|
||||
-- , browserstartdelay
|
||||
, hledgerorgurl
|
||||
, manualurl
|
||||
) where
|
||||
|
||||
import Data.Monoid (mempty) --, mappend)
|
||||
import Data.Text (Text,pack)
|
||||
import Language.Haskell.TH.Syntax
|
||||
import System.Directory (doesFileExist)
|
||||
import Text.Printf (printf)
|
||||
import qualified Text.Hamlet as H
|
||||
import qualified Text.Cassius as H
|
||||
import qualified Text.Julius as H
|
||||
import qualified Text.Lucius as H
|
||||
import Yesod.Widget (addWidget, addCassius, addJulius, addLucius)
|
||||
|
||||
|
||||
-- browserstartdelay = 100000 -- microseconds
|
||||
|
||||
hledgerorgurl, manualurl :: String
|
||||
hledgerorgurl = "http://hledger.org"
|
||||
manualurl = hledgerorgurl++"/MANUAL.html"
|
||||
|
||||
-- | The default TCP port to listen on. May be overridden with --port.
|
||||
defport :: Int
|
||||
defport = 5000
|
||||
|
||||
defhost :: String
|
||||
defhost = "localhost"
|
||||
|
||||
-- | The default base URL for your application. This will usually be different for
|
||||
-- development and production. Yesod automatically constructs URLs for you,
|
||||
-- so this value must be accurate to create valid links.
|
||||
-- For hledger-web this is usually overridden with --base-url.
|
||||
defapproot :: Text
|
||||
defapproot = pack $ printf "http://%s:%d" defhost defport
|
||||
-- #ifdef PRODUCTION
|
||||
-- #else
|
||||
-- #endif
|
||||
|
||||
-- | Hard-coded data directory path. This must be in your current dir when
|
||||
-- you compile. At run time it's also required but we'll auto-create it.
|
||||
datadir :: FilePath
|
||||
datadir = "./.hledger/web/"
|
||||
|
||||
-- | The location of static files on your system. This is a file system
|
||||
-- path. The default value works properly with your scaffolded site.
|
||||
staticdir :: FilePath
|
||||
staticdir = datadir++"static"
|
||||
|
||||
-- | The base URL for your static files. As you can see by the default
|
||||
-- value, this can simply be "static" appended to your application root.
|
||||
-- A powerful optimization can be serving static files from a separate
|
||||
-- domain name. This allows you to use a web server optimized for static
|
||||
-- files, more easily set expires and cache values, and avoid possibly
|
||||
-- costly transference of cookies on static files. For more information,
|
||||
-- please see:
|
||||
-- http://code.google.com/speed/page-speed/docs/request.html#ServeFromCookielessDomain
|
||||
--
|
||||
-- If you change the resource pattern for StaticR in hledger-web.hs, you will
|
||||
-- have to make a corresponding change here.
|
||||
--
|
||||
-- To see how this value is used, see urlRenderOverride in hledger-web.hs
|
||||
-- staticroot :: Text
|
||||
-- staticroot = defapproot `mappend` "/static"
|
||||
|
||||
|
||||
|
||||
-- The rest of this file contains settings which rarely need changing by a
|
||||
-- user.
|
||||
|
||||
-- The following three functions are used for calling HTML, CSS and
|
||||
-- Javascript templates from your Haskell code. During development,
|
||||
-- the "Debug" versions of these functions are used so that changes to
|
||||
-- the templates are immediately reflected in an already running
|
||||
-- application. When making a production compile, the non-debug version
|
||||
-- is used for increased performance.
|
||||
--
|
||||
-- You can see an example of how to call these functions in Handler/Root.hs
|
||||
--
|
||||
-- Note: due to polymorphic Hamlet templates, hamletFileDebug is no longer
|
||||
-- used; to get the same auto-loading effect, it is recommended that you
|
||||
-- use the devel server.
|
||||
|
||||
toHamletFile, toCassiusFile, toJuliusFile, toLuciusFile :: String -> FilePath
|
||||
toHamletFile x = datadir++"templates/" ++ x ++ ".hamlet"
|
||||
toCassiusFile x = datadir++"templates/" ++ x ++ ".cassius"
|
||||
toJuliusFile x = datadir++"templates/" ++ x ++ ".julius"
|
||||
toLuciusFile x = datadir++"templates/" ++ x ++ ".lucius"
|
||||
|
||||
hamletFile :: FilePath -> Q Exp
|
||||
hamletFile = H.hamletFile . toHamletFile
|
||||
|
||||
cassiusFile :: FilePath -> Q Exp
|
||||
#ifdef PRODUCTION
|
||||
cassiusFile = H.cassiusFile . toCassiusFile
|
||||
#else
|
||||
cassiusFile = H.cassiusFileDebug . toCassiusFile
|
||||
#endif
|
||||
|
||||
luciusFile :: FilePath -> Q Exp
|
||||
#ifdef PRODUCTION
|
||||
luciusFile = H.luciusFile . toLuciusFile
|
||||
#else
|
||||
luciusFile = H.luciusFileDebug . toLuciusFile
|
||||
#endif
|
||||
|
||||
juliusFile :: FilePath -> Q Exp
|
||||
#ifdef PRODUCTION
|
||||
juliusFile = H.juliusFile . toJuliusFile
|
||||
#else
|
||||
juliusFile = H.juliusFileDebug . toJuliusFile
|
||||
#endif
|
||||
|
||||
widgetFile :: FilePath -> Q Exp
|
||||
widgetFile x = do
|
||||
let h = unlessExists toHamletFile hamletFile
|
||||
let c = unlessExists toCassiusFile cassiusFile
|
||||
let j = unlessExists toJuliusFile juliusFile
|
||||
let l = unlessExists toLuciusFile luciusFile
|
||||
[|addWidget $h >> addCassius $c >> addJulius $j >> addLucius $l|]
|
||||
where
|
||||
unlessExists tofn f = do
|
||||
e <- qRunIO $ doesFileExist $ tofn x
|
||||
if e then f x else [|mempty|]
|
18
hledger-web/StaticFiles.hs
Normal file
18
hledger-web/StaticFiles.hs
Normal file
@ -0,0 +1,18 @@
|
||||
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies #-}
|
||||
{-|
|
||||
|
||||
This module exports routes for all the files in the static directory at
|
||||
compile time, allowing compile-time verification that referenced files
|
||||
exist. However, any files added during run-time can't be accessed this
|
||||
way; use their FilePath or URL to access them.
|
||||
|
||||
This is a separate module to satisfy template haskell requirements.
|
||||
|
||||
-}
|
||||
module StaticFiles where
|
||||
|
||||
import Yesod.Helpers.Static
|
||||
|
||||
import Settings (staticdir)
|
||||
|
||||
$(staticFiles staticdir)
|
@ -1,5 +1,5 @@
|
||||
name: hledger-web
|
||||
version: 0.14
|
||||
version: 0.14.98
|
||||
category: Finance
|
||||
synopsis: A web interface for the hledger accounting tool.
|
||||
description:
|
||||
@ -37,21 +37,31 @@ Flag production
|
||||
Description: Build in production mode, which reads template files only once at startup.
|
||||
Default: False
|
||||
|
||||
Flag devel
|
||||
Description: Build for use with "yesod devel"
|
||||
Default: False
|
||||
|
||||
executable hledger-web
|
||||
main-is: hledger-web.hs
|
||||
ghc-options: -threaded -W
|
||||
-- hs-source-dirs: ., config
|
||||
if flag(devel)
|
||||
Buildable: False
|
||||
if flag(production)
|
||||
cpp-options: -DPRODUCTION
|
||||
cpp-options: -DPRODUCTION
|
||||
ghc-options: -Wall -threaded -O2
|
||||
else
|
||||
ghc-options: -W -threaded
|
||||
other-modules:
|
||||
Hledger.Web.Main
|
||||
Hledger.Web.App
|
||||
Hledger.Web.Files
|
||||
Hledger.Web.Settings
|
||||
App
|
||||
EmbeddedFiles
|
||||
Settings
|
||||
StaticFiles
|
||||
Handlers
|
||||
build-depends:
|
||||
hledger == 0.14
|
||||
hledger == 0.14.98
|
||||
,hledger-lib == 0.14
|
||||
-- ,HUnit
|
||||
,base >= 3 && < 5
|
||||
,base >= 4 && < 5
|
||||
,bytestring
|
||||
-- ,containers
|
||||
-- ,csv
|
||||
@ -65,15 +75,66 @@ executable hledger-web
|
||||
-- ,regexpr >= 0.5.1
|
||||
,safe >= 0.2
|
||||
-- ,split == 0.1.*
|
||||
,text
|
||||
-- ,time
|
||||
-- ,utf8-string >= 0.3.5 && < 0.4
|
||||
,io-storage >= 0.3 && < 0.4
|
||||
,yesod >= 0.8 && < 0.9
|
||||
-- ,convertible-text >= 0.3.0.1 && < 0.4
|
||||
-- ,data-object >= 0.3.1.2 && < 0.4
|
||||
,failure >= 0.1 && < 0.2
|
||||
-- ,persistent == 0.2.*
|
||||
-- ,persistent-sqlite == 0.2.*
|
||||
,template-haskell >= 2.4 && < 2.6
|
||||
,wai-extra == 0.4.*
|
||||
,file-embed == 0.0.*
|
||||
,template-haskell >= 2.4 && < 2.6
|
||||
-- ,yesod >= 0.8 && < 0.9
|
||||
,yesod-core >= 0.8 && < 0.9
|
||||
,yesod-static
|
||||
,hamlet == 0.8.*
|
||||
,transformers
|
||||
,wai
|
||||
,wai-extra == 0.4.*
|
||||
,warp
|
||||
-- , blaze-builder
|
||||
-- , web-routes
|
||||
|
||||
library
|
||||
if flag(devel)
|
||||
Buildable: True
|
||||
else
|
||||
Buildable: False
|
||||
exposed-modules:
|
||||
Controller
|
||||
other-modules:
|
||||
App
|
||||
EmbeddedFiles
|
||||
Settings
|
||||
StaticFiles
|
||||
Handlers
|
||||
|
||||
-- executable hledger-web
|
||||
-- if flag(devel)
|
||||
-- Buildable: False
|
||||
|
||||
-- if flag(production)
|
||||
-- cpp-options: -DPRODUCTION
|
||||
-- ghc-options: -Wall -threaded -O2
|
||||
-- else
|
||||
-- ghc-options: -Wall -threaded
|
||||
|
||||
-- main-is: config/hledger-web.hs
|
||||
-- hs-source-dirs: ., config
|
||||
|
||||
-- build-depends: base >= 4 && < 5
|
||||
-- , yesod-core >= 0.8 && < 0.9
|
||||
-- , yesod-static
|
||||
-- , wai-extra
|
||||
-- , directory
|
||||
-- , bytestring
|
||||
-- , text
|
||||
-- , template-haskell
|
||||
-- , hamlet
|
||||
-- , web-routes
|
||||
-- , transformers
|
||||
-- , wai
|
||||
-- , warp
|
||||
-- , blaze-builder
|
||||
|
||||
|
||||
|
@ -1,2 +1,109 @@
|
||||
#!/usr/bin/env runhaskell
|
||||
import Hledger.Web.Main (main)
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-|
|
||||
hledger-web - a hledger add-on providing a web interface.
|
||||
Copyright (c) 2007-2011 Simon Michael <simon@joyful.com>
|
||||
Released under GPL version 3 or later.
|
||||
-}
|
||||
|
||||
module Main
|
||||
where
|
||||
|
||||
import Controller (withApp)
|
||||
import Network.Wai.Handler.Warp (run)
|
||||
#if PRODUCTION
|
||||
#else
|
||||
import Network.Wai.Middleware.Debug (debug)
|
||||
#endif
|
||||
|
||||
import Prelude hiding (putStr, putStrLn)
|
||||
-- import Control.Concurrent (forkIO, threadDelay)
|
||||
import Data.Text(pack)
|
||||
import System.Exit (exitFailure)
|
||||
import System.IO.Storage (withStore, putValue,)
|
||||
import System.Console.GetOpt
|
||||
import Yesod.Helpers.Static
|
||||
|
||||
import Hledger.Cli.Options
|
||||
import Hledger.Cli.Utils (withJournalDo) --, openBrowserOn)
|
||||
import Hledger.Cli.Version (progversionstr, binaryfilename)
|
||||
import Hledger.Data
|
||||
import Hledger.Data.UTF8 (putStr, putStrLn)
|
||||
|
||||
import App
|
||||
import EmbeddedFiles (createFilesIfMissing)
|
||||
import Settings (defhost, defport, datadir, staticdir) -- , browserstartdelay)
|
||||
|
||||
|
||||
progname_web = progname_cli ++ "-web"
|
||||
|
||||
options_web :: [OptDescr Opt]
|
||||
options_web = [
|
||||
Option "" ["base-url"] (ReqArg BaseUrl "URL") "use this base url (default http://localhost:PORT)"
|
||||
,Option "" ["port"] (ReqArg Port "N") "serve on tcp port N (default 5000)"
|
||||
]
|
||||
|
||||
usage_preamble_web =
|
||||
"Usage: hledger-web [OPTIONS] [PATTERNS]\n" ++
|
||||
"\n" ++
|
||||
"Reads your ~/.journal file, or another specified by $LEDGER or -f, and\n" ++
|
||||
"starts a web ui server. Also attempts to start a web browser (unless --debug).\n" ++
|
||||
"\n"
|
||||
|
||||
usage_options_web = usageInfo "hledger-web options:" options_web ++ "\n"
|
||||
|
||||
usage_web = concat [
|
||||
usage_preamble_web
|
||||
,usage_options_web
|
||||
,usage_options_cli
|
||||
,usage_postscript_cli
|
||||
]
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
(opts, args) <- parseArgumentsWith $ options_cli++options_web
|
||||
run opts args
|
||||
where
|
||||
run opts args
|
||||
| Help `elem` opts = putStr usage_web
|
||||
| Version `elem` opts = putStrLn $ progversionstr progname_web
|
||||
| BinaryFilename `elem` opts = putStrLn $ binaryfilename progname_web
|
||||
| otherwise = withJournalDo opts args "web" web
|
||||
|
||||
-- | The web command.
|
||||
web :: [Opt] -> [String] -> Journal -> IO ()
|
||||
web opts args j = do
|
||||
created <- createFilesIfMissing
|
||||
if created
|
||||
then do
|
||||
putStrLn $ "Installing support files in "++datadir++" - done, please run again."
|
||||
exitFailure
|
||||
else do
|
||||
putStrLn $ "Using support files in "++datadir
|
||||
let host = defhost
|
||||
port = fromMaybe defport $ portFromOpts opts
|
||||
baseurl = fromMaybe (printf "http://%s:%d" host port) $ baseUrlFromOpts opts
|
||||
-- unless (Debug `elem` opts) $ forkIO (browser baseurl) >> return ()
|
||||
server baseurl port opts args j
|
||||
|
||||
-- browser :: String -> IO ()
|
||||
-- browser baseurl = do
|
||||
-- threadDelay $ fromIntegral browserstartdelay
|
||||
-- putStrLn "Attempting to start a web browser"
|
||||
-- openBrowserOn baseurl >> return ()
|
||||
|
||||
server :: String -> Int -> [Opt] -> [String] -> Journal -> IO ()
|
||||
server baseurl port opts args j = do
|
||||
printf "Starting http server on port %d with base url %s\n" port baseurl
|
||||
let a = App{getStatic=static staticdir
|
||||
,appRoot=pack baseurl
|
||||
,appOpts=opts
|
||||
,appArgs=args
|
||||
,appJournal=j
|
||||
}
|
||||
withStore "hledger" $ do
|
||||
putValue "hledger" "journal" j
|
||||
#if PRODUCTION
|
||||
withApp a (run port)
|
||||
#else
|
||||
withApp a (run port . debug)
|
||||
#endif
|
||||
|
0
hledger-web/models
Normal file
0
hledger-web/models
Normal file
7
hledger-web/routes
Normal file
7
hledger-web/routes
Normal file
@ -0,0 +1,7 @@
|
||||
/static StaticR Static getStatic
|
||||
/favicon.ico FaviconR GET
|
||||
/robots.txt RobotsR GET
|
||||
/ RootR GET
|
||||
/accounts AccountsOnlyR GET
|
||||
/journal JournalR GET
|
||||
/register RegisterR GET
|
Loading…
Reference in New Issue
Block a user