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.Cmd (system)
 | 
				
			||||||
import System.Info (os)
 | 
					import System.Info (os)
 | 
				
			||||||
import System.Exit
 | 
					import System.Exit
 | 
				
			||||||
 | 
					import Network.HTTP (urlEncode, urlDecode, urlEncodeVars)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Ledger
 | 
					import Ledger
 | 
				
			||||||
import Options
 | 
					import Options
 | 
				
			||||||
@ -27,72 +28,87 @@ import BalanceCommand
 | 
				
			|||||||
import RegisterCommand
 | 
					import RegisterCommand
 | 
				
			||||||
import PrintCommand
 | 
					import PrintCommand
 | 
				
			||||||
import HistogramCommand
 | 
					import HistogramCommand
 | 
				
			||||||
 | 
					import Utils (filterAndCacheLedgerWithOpts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tcpport = 5000
 | 
					tcpport = 5000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
web :: [Opt] -> [String] -> Ledger -> IO ()
 | 
					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
 | 
					  if Debug `elem` opts
 | 
				
			||||||
     then do
 | 
					   then do
 | 
				
			||||||
       putStrLn $ printf "starting web server on port %d in debug mode" tcpport
 | 
					    -- just run the server in the foreground
 | 
				
			||||||
       simpleHTTP nullConf{port=tcpport} handlers
 | 
					    putStrLn $ printf "starting web server on port %d in debug mode" tcpport
 | 
				
			||||||
     else do
 | 
					    simpleHTTP nullConf{port=tcpport} $ webHandlers opts args l t
 | 
				
			||||||
       putStrLn $ printf "starting web server on port %d" tcpport
 | 
					   else do
 | 
				
			||||||
       tid <- forkIO $ simpleHTTP nullConf{port=tcpport} handlers
 | 
					    -- start the server (in background, so we can..) then start the web browser
 | 
				
			||||||
       putStrLn "starting web browser"
 | 
					    putStrLn $ printf "starting web server on port %d" tcpport
 | 
				
			||||||
       openBrowserOn $ printf "http://localhost:%d/balance" tcpport
 | 
					    tid <- forkIO $ simpleHTTP nullConf{port=tcpport} $ webHandlers opts args l t
 | 
				
			||||||
       waitForTermination
 | 
					    putStrLn "starting web browser"
 | 
				
			||||||
       putStrLn "shutting down web server..."
 | 
					    openBrowserOn $ printf "http://localhost:%d/" tcpport
 | 
				
			||||||
       killThread tid
 | 
					    waitForTermination
 | 
				
			||||||
       putStrLn "shutdown complete"
 | 
					    putStrLn "shutting down web server..."
 | 
				
			||||||
 | 
					    killThread tid
 | 
				
			||||||
 | 
					    putStrLn "shutdown complete"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    where
 | 
					webHandlers :: [Opt] -> [String] -> Ledger -> LocalTime -> ServerPartT IO Response
 | 
				
			||||||
      handlers :: ServerPartT IO Response
 | 
					webHandlers opts args l t = msum
 | 
				
			||||||
      handlers = msum
 | 
					 [
 | 
				
			||||||
       [methodSP GET $ withDataFn (look "a") $ \a -> templatise $ balancereport [a]
 | 
					  methodSP GET $ view showBalanceReport
 | 
				
			||||||
       ,methodSP GET $ templatise $ balancereport []
 | 
					 ,dir "balance" $ view showBalanceReport
 | 
				
			||||||
       ,dir "print" $ withDataFn (look "a") $ \a -> templatise $ printreport [a]
 | 
					 ,dir "register" $ view showRegisterReport
 | 
				
			||||||
       ,dir "print" $ templatise $ printreport []
 | 
					 ,dir "print" $ view showLedgerTransactions
 | 
				
			||||||
       ,dir "register" $ withDataFn (look "a") $ \a -> templatise $ registerreport [a]
 | 
					 ,dir "histogram" $ view showHistogram
 | 
				
			||||||
       ,dir "register" $ templatise $ registerreport []
 | 
					 ]
 | 
				
			||||||
       ,dir "balance" $ withDataFn (look "a") $ \a -> templatise $ balancereport [a]
 | 
					 where 
 | 
				
			||||||
       ,dir "balance" $ templatise $ balancereport []
 | 
					   view f = withDataFn rqdata $ render f
 | 
				
			||||||
       ,dir "histogram" $ withDataFn (look "a") $ \a -> templatise $ histogramreport [a]
 | 
					   render f (a,p) = layout (a, p) $ f opts' args' l'
 | 
				
			||||||
       ,dir "histogram" $ templatise $ histogramreport []
 | 
					       where
 | 
				
			||||||
       ]
 | 
					         opts' = opts ++ [Period p]
 | 
				
			||||||
      printreport apats    = showLedgerTransactions opts (apats ++ args) l
 | 
					         args' = args ++ (map urlDecode $ words a)
 | 
				
			||||||
      registerreport apats = showRegisterReport opts (apats ++ args) l
 | 
					         -- re-filter the full ledger
 | 
				
			||||||
      balancereport []  = showBalanceReport opts args l
 | 
					         l' = filterAndCacheLedgerWithOpts opts' args' t (rawledgertext l) (rawledger 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
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
templatise :: String -> ServerPartT IO Response
 | 
					rqdata = do
 | 
				
			||||||
templatise s = 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
 | 
					  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 :: (String, String) -> Request -> String -> String
 | 
				
			||||||
maintemplate r = printf (unlines
 | 
					maintemplate (a,p) r = printf (unlines
 | 
				
			||||||
  ["<div style=float:right>"
 | 
					  ["<div style=\"float:right;text-align:right;\">"
 | 
				
			||||||
  ,"<form action=%s>search: <input name=a value=%s></form>"
 | 
					  ,"<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>"
 | 
				
			||||||
  ,"<div align=center style=width:100%%>"
 | 
					  ,"<div style=\"width:100%%; font-weight:bold;\">"
 | 
				
			||||||
  ," <a href=balance>balance</a>"
 | 
					  ," <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>"
 | 
					  ,"</div>"
 | 
				
			||||||
  ,"<pre>%s</pre>"
 | 
					  ,"<pre>%s</pre>"
 | 
				
			||||||
  ])
 | 
					  ]) u a p q q q q
 | 
				
			||||||
  (dropWhile (=='/') $ rqUri r)
 | 
					    where
 | 
				
			||||||
  (fromMaybe "" $ queryValue "a" r)
 | 
					      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 :: String -> Request -> [String]
 | 
				
			||||||
queryValues q r = map (B.unpack . inputValue . snd) $ filter ((==q).fst) $ rqInputs r
 | 
					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,
 | 
					  Build-Depends:  base, containers, haskell98, directory, parsec,
 | 
				
			||||||
                  regex-compat, regexpr>=0.5.1, old-locale, time,
 | 
					                  regex-compat, regexpr>=0.5.1, old-locale, time,
 | 
				
			||||||
                  HUnit, mtl, bytestring, filepath, process, testpack,
 | 
					                  HUnit, mtl, bytestring, filepath, process, testpack,
 | 
				
			||||||
                  regex-pcre, csv, split, utf8-string
 | 
					                  regex-pcre, csv, split, utf8-string, http
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Other-Modules:  
 | 
					  Other-Modules:  
 | 
				
			||||||
                  AddCommand
 | 
					                  AddCommand
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user