web: code cleanup, better web ui supporting full patterns & period expressions
New dependency: http.
This commit is contained in:
		
							parent
							
								
									4517cab686
								
							
						
					
					
						commit
						71e7f2b293
					
				
							
								
								
									
										116
									
								
								WebCommand.hs
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								WebCommand.hs
									
									
									
									
									
								
							| @ -20,6 +20,7 @@ import Happstack.State.Control (waitForTermination) | ||||
| import System.Cmd (system) | ||||
| import System.Info (os) | ||||
| import System.Exit | ||||
| import Network.HTTP (urlEncode, urlDecode, urlEncodeVars) | ||||
| 
 | ||||
| import Ledger | ||||
| import Options | ||||
| @ -27,72 +28,87 @@ import BalanceCommand | ||||
| import RegisterCommand | ||||
| import PrintCommand | ||||
| import HistogramCommand | ||||
| import Utils (filterAndCacheLedgerWithOpts) | ||||
| 
 | ||||
| 
 | ||||
| tcpport = 5000 | ||||
| 
 | ||||
| web :: [Opt] -> [String] -> Ledger -> IO () | ||||
| web opts args l = | ||||
| web opts args l = do | ||||
|   t <- getCurrentLocalTime -- how to get this per request ? | ||||
|   if Debug `elem` opts | ||||
|      then do | ||||
|        putStrLn $ printf "starting web server on port %d in debug mode" tcpport | ||||
|        simpleHTTP nullConf{port=tcpport} handlers | ||||
|      else do | ||||
|        putStrLn $ printf "starting web server on port %d" tcpport | ||||
|        tid <- forkIO $ simpleHTTP nullConf{port=tcpport} handlers | ||||
|        putStrLn "starting web browser" | ||||
|        openBrowserOn $ printf "http://localhost:%d/balance" tcpport | ||||
|        waitForTermination | ||||
|        putStrLn "shutting down web server..." | ||||
|        killThread tid | ||||
|        putStrLn "shutdown complete" | ||||
|    then do | ||||
|     -- just run the server in the foreground | ||||
|     putStrLn $ printf "starting web server on port %d in debug mode" tcpport | ||||
|     simpleHTTP nullConf{port=tcpport} $ webHandlers opts args l t | ||||
|    else do | ||||
|     -- start the server (in background, so we can..) then start the web browser | ||||
|     putStrLn $ printf "starting web server on port %d" tcpport | ||||
|     tid <- forkIO $ simpleHTTP nullConf{port=tcpport} $ webHandlers opts args l t | ||||
|     putStrLn "starting web browser" | ||||
|     openBrowserOn $ printf "http://localhost:%d/" tcpport | ||||
|     waitForTermination | ||||
|     putStrLn "shutting down web server..." | ||||
|     killThread tid | ||||
|     putStrLn "shutdown complete" | ||||
| 
 | ||||
|     where | ||||
|       handlers :: ServerPartT IO Response | ||||
|       handlers = msum | ||||
|        [methodSP GET $ withDataFn (look "a") $ \a -> templatise $ balancereport [a] | ||||
|        ,methodSP GET $ templatise $ balancereport [] | ||||
|        ,dir "print" $ withDataFn (look "a") $ \a -> templatise $ printreport [a] | ||||
|        ,dir "print" $ templatise $ printreport [] | ||||
|        ,dir "register" $ withDataFn (look "a") $ \a -> templatise $ registerreport [a] | ||||
|        ,dir "register" $ templatise $ registerreport [] | ||||
|        ,dir "balance" $ withDataFn (look "a") $ \a -> templatise $ balancereport [a] | ||||
|        ,dir "balance" $ templatise $ balancereport [] | ||||
|        ,dir "histogram" $ withDataFn (look "a") $ \a -> templatise $ histogramreport [a] | ||||
|        ,dir "histogram" $ templatise $ histogramreport [] | ||||
|        ] | ||||
|       printreport apats    = showLedgerTransactions opts (apats ++ args) l | ||||
|       registerreport apats = showRegisterReport opts (apats ++ args) l | ||||
|       balancereport []  = showBalanceReport opts args l | ||||
|       balancereport apats  = showBalanceReport opts (apats ++ args) l' | ||||
|           where l' = cacheLedger apats (rawledger l) -- re-filter by account pattern each time | ||||
|       histogramreport []  = showHistogram opts args l | ||||
|       histogramreport apats  = showHistogram opts (apats ++ args) l' | ||||
|           where l' = cacheLedger apats (rawledger l) -- re-filter by account pattern each time | ||||
| webHandlers :: [Opt] -> [String] -> Ledger -> LocalTime -> ServerPartT IO Response | ||||
| webHandlers opts args l t = msum | ||||
|  [ | ||||
|   methodSP GET $ view showBalanceReport | ||||
|  ,dir "balance" $ view showBalanceReport | ||||
|  ,dir "register" $ view showRegisterReport | ||||
|  ,dir "print" $ view showLedgerTransactions | ||||
|  ,dir "histogram" $ view showHistogram | ||||
|  ] | ||||
|  where  | ||||
|    view f = withDataFn rqdata $ render f | ||||
|    render f (a,p) = layout (a, p) $ f opts' args' l' | ||||
|        where | ||||
|          opts' = opts ++ [Period p] | ||||
|          args' = args ++ (map urlDecode $ words a) | ||||
|          -- re-filter the full ledger | ||||
|          l' = filterAndCacheLedgerWithOpts opts' args' t (rawledgertext l) (rawledger l) | ||||
| 
 | ||||
| templatise :: String -> ServerPartT IO Response | ||||
| templatise s = do | ||||
| rqdata = do | ||||
|      a <- look "a" `mplus` return "" -- filter patterns | ||||
|      p <- look "p" `mplus` return "" -- reporting period | ||||
|      return (a,p) | ||||
| 
 | ||||
| layout :: (String, String) -> String -> ServerPartT IO Response | ||||
| layout (a,p) s = do | ||||
|   r <- askRq | ||||
|   return $ setHeader "Content-Type" "text/html" $ toResponse $ maintemplate r s | ||||
|   return $ setHeader "Content-Type" "text/html" $ toResponse $ maintemplate (a,p) r s | ||||
| 
 | ||||
| maintemplate :: Request -> String -> String | ||||
| maintemplate r = printf (unlines | ||||
|   ["<div style=float:right>" | ||||
|   ,"<form action=%s>search: <input name=a value=%s></form>" | ||||
| maintemplate :: (String, String) -> Request -> String -> String | ||||
| maintemplate (a,p) r = printf (unlines | ||||
|   ["<div style=\"float:right;text-align:right;\">" | ||||
|   ,"<form action=%s>" | ||||
|   ,"  filter by: <input name=a size=30 value=\"%s\">" | ||||
|   ,"  reporting period: <input name=p size=30 value=\"%s\">" | ||||
|   ,resetlink | ||||
|   ,"</form>" | ||||
|   ,"</div>" | ||||
|   ,"<div align=center style=width:100%%>" | ||||
|   ," <a href=balance>balance</a>" | ||||
|   ,"<div style=\"width:100%%; font-weight:bold;\">" | ||||
|   ," <a href=balance%s>balance</a>" | ||||
|   ,"|" | ||||
|   ," <a href=register>register</a>" | ||||
|   ," <a href=register%s>register</a>" | ||||
|   ,"|" | ||||
|   ," <a href=print>print</a>" | ||||
|   ," <a href=print%s>print</a>" | ||||
|   ,"|" | ||||
|   ," <a href=histogram>histogram</a>" | ||||
|   ," <a href=histogram%s>histogram</a>" | ||||
|   ,"</div>" | ||||
|   ,"<pre>%s</pre>" | ||||
|   ]) | ||||
|   (dropWhile (=='/') $ rqUri r) | ||||
|   (fromMaybe "" $ queryValue "a" r) | ||||
|   ]) u a p q q q q | ||||
|     where | ||||
|       u = dropWhile (=='/') $ rqUri r | ||||
|       -- another way to get them | ||||
|       -- a = fromMaybe "" $ queryValue "a" r | ||||
|       -- p = fromMaybe "" $ queryValue "p" r | ||||
|       q' = intercalate "&" $ if null a then [] else [(("a="++).urlEncode) a] ++ if null p then [] else [(("p="++).urlEncode) p] | ||||
|       q = if null q' then "" else '?':q' | ||||
|       resetlink | null a && null p = "" | ||||
|                 | otherwise = printf "  <a href=%s>reset</a>" u | ||||
| 
 | ||||
| queryValues :: String -> Request -> [String] | ||||
| queryValues q r = map (B.unpack . inputValue . snd) $ filter ((==q).fst) $ rqInputs r | ||||
|  | ||||
| @ -53,7 +53,7 @@ Executable hledger | ||||
|   Build-Depends:  base, containers, haskell98, directory, parsec, | ||||
|                   regex-compat, regexpr>=0.5.1, old-locale, time, | ||||
|                   HUnit, mtl, bytestring, filepath, process, testpack, | ||||
|                   regex-pcre, csv, split, utf8-string | ||||
|                   regex-pcre, csv, split, utf8-string, http | ||||
| 
 | ||||
|   Other-Modules:   | ||||
|                   AddCommand | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user