nomyx-web-1.0.0: src/Nomyx/Web/MainPage.hs
{-# LANGUAGE DoAndIfThenElse #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Nomyx.Web.MainPage (launchWebServer) where
import Control.Applicative
import Control.Concurrent.STM
import Control.Monad
import Control.Monad.Error
import Control.Monad.State
import Control.Lens
import Data.List
import Data.Maybe
import Data.Monoid
import Data.String
import Data.Text as T (Text, pack, unpack, length)
import Happstack.Authenticate.OpenId.Route (initOpenId)
import Happstack.Authenticate.Password.Route (initPassword)
import Happstack.Authenticate.Password.Core(PasswordConfig(..), PasswordState)
import Happstack.Authenticate.Route (initAuthentication)
import Happstack.Authenticate.Core (AuthenticateURL(..), AuthenticateConfig(..), AuthenticateState, Email(..), User(..), Username(..), UserId(..), GetAuthenticateState(..), decodeAndVerifyToken, tokenUser, usernamePolicy)
import Happstack.Server as HS
import Nomyx.Language
import Nomyx.Core.Engine hiding (JoinGame,
LeaveGame)
import Nomyx.Core.Profile as Profile
import qualified Nomyx.Core.Session as S
import Nomyx.Core.Types as T hiding (JoinGame, LeaveGame)
import Nomyx.Core.Utils
import Nomyx.Core.Engine.Evaluation
import Nomyx.Web.Common as W
import Nomyx.Web.Game.Details
import Nomyx.Web.Game.Infos
import Nomyx.Web.Game.Actions
import Nomyx.Web.Game.Templates
import Nomyx.Web.Game.Rules
import Nomyx.Web.Game.Modules
import qualified Nomyx.Web.Help as Help
import Nomyx.Web.Login
import Nomyx.Web.NewGame
import Nomyx.Web.Settings
import Nomyx.Web.Types
import qualified Nomyx.Auth as Auth
import Paths_nomyx_language
import Prelude hiding (div)
import Safe
import System.FilePath
import Text.Blaze.Html5 hiding (head, map)
import qualified Text.Blaze.Html5 as H
import Text.Blaze.Html5.Attributes hiding (dir, id)
import qualified Text.Blaze.Html5.Attributes as A
import Web.Routes.Happstack
import Web.Routes.PathInfo
import Web.Routes.RouteT (runRouteT)
import Web.Routes.Site
import Imprevu.Happstack.Forms
import Imprevu.Happstack.Types
import Imprevu.Evaluation
import qualified Nomyx.Core.Engine.Types as ET
import qualified Nomyx.Core.Session as S
default (Integer, Double, T.Text)
viewMulti :: (Maybe PlayerNumber) -> FilePath -> GameTab -> GameName -> Session -> RoutedNomyxServer Html
viewMulti mpn saveDir gt gn s = do
(isAdmin, lr, lib) <- case mpn of
Just pn -> do
pfd <- getProfile s pn
let isAdmin = _pIsAdmin $ fromJustNote "viewMulti" pfd
let lr = _pLastRule $ fromJustNote "viewMulti" pfd
let lib = _pLibrary $ fromJustNote "viewMulti" pfd
return (isAdmin, lr, lib)
Nothing -> return (False, Nothing, _mLibrary $ _multi s)
let gi = fromJust $ getGameByName gn s --TODO fix
gns <- viewGamesTab gi isAdmin saveDir mpn
vg <- viewGameInfo gi mpn lr isAdmin gt lib
ok $ do
div ! A.id "gameList" $ gns
vg
viewGamesTab :: GameInfo -> Bool -> FilePath -> (Maybe PlayerNumber) -> RoutedNomyxServer Html
viewGamesTab gi isAdmin saveDir mpn = do
let g = getGame gi
let gn = _gameName g
ok $ do
table $ do
tr $ td ! A.class_ "buttonTD" $ H.a "Home " ! A.class_ "button" ! href (toValue $ showRelURL $ Menu Home gn)
tr $ td ! A.class_ "buttonTD" $ H.a "Constitution " ! A.class_ "button" ! href (toValue $ showRelURL $ Menu Rules gn)
tr $ td ! A.class_ "buttonTD" $ H.a "Actions " ! A.class_ "button" ! href (toValue $ showRelURL $ Menu Actions gn)
tr $ td ! A.class_ "buttonTD" $ H.a "Library " ! A.class_ "button" ! href (toValue $ showRelURL $ Menu Lib gn)
-- br >> b "Help files:" >> br
-- H.a "Nomyx language" ! (href "/html/Language-Nomyx.html") ! target "_blank" >> br
viewGameInfo :: GameInfo -> (Maybe PlayerNumber) -> Maybe LastRule -> Bool -> GameTab -> Library -> RoutedNomyxServer Html
viewGameInfo gi mpn mlr isAdmin gt lib = do
let g = getGame gi
let gn = _gameName g
let pi = join $ (Profile.getPlayerInfo g) <$> mpn
let isGameAdmin = isAdmin || maybe False (== mpn) (Just $ _ownedBy gi)
let playAs = mpn >> maybe Nothing _playingAs pi
let pn = fromMaybe 0 mpn
vrf <- viewLibrary lib mlr gn isGameAdmin
vms <- viewModules lib mlr gn isGameAdmin
vios <- viewIOs (fromMaybe pn playAs) g
vgd <- viewGameDesc g mpn playAs isGameAdmin
vrs <- viewAllRules pn g
ok $ case gt of
Home -> div ! A.id "gameDescGameDiv" ! A.class_ "game" $ vgd
Rules -> div ! A.id "rulesGameDiv" ! A.class_ "game" $ vrs
Actions -> div ! A.id "iosGameDiv" ! A.class_ "game" $ vios
Lib -> div ! A.id "newRuleGameDiv" ! A.class_ "game" $ vrf
Modules -> div ! A.id "moduleDiv" ! A.class_ "game" $ vms
Details -> div ! A.id "detailsGameDiv" ! A.class_ "game" $ viewDetails pn g
joinGame :: GameName -> RoutedNomyxServer Response
joinGame gn = do
pn <- fromJust <$> getPlayerNumber
webCommand (S.joinGame gn pn)
seeOther (showRelURL MainPage) $ toResponse "Redirecting..."
leaveGame :: GameName -> RoutedNomyxServer Response
leaveGame gn = do
pn <- fromJust <$> getPlayerNumber
webCommand (S.leaveGame gn pn)
seeOther (showRelURL MainPage) $ toResponse "Redirecting..."
delGame :: GameName -> RoutedNomyxServer Response
delGame gn = do
webCommand (S.delGame gn)
seeOther (showRelURL MainPage) $ toResponse "Redirecting..."
nomyxPage :: Maybe GameName -> GameTab -> RoutedNomyxServer Response
nomyxPage mgn tab = do
mpn <- getPlayerNumber
s <- getSession
let saveDir = _saveDir $ _mSettings $ _multi s
name <- case mpn of
Just pn -> liftIO $ Profile.getPlayerName pn s
Nothing -> return "Guest"
let gn = maybe (_gameName $ _game $ _loggedGame $ head $ _gameInfos $ _multi s) id mgn
m <- viewMulti mpn saveDir tab gn s
title <- titleBar name gn
mainPage' "Nomyx: the game where you can change the rules"
title
False
(H.div $ m)
titleBar :: PlayerName -> GameName -> RoutedNomyxServer Html
titleBar name gn = ok $ table ! A.id "headerTitle" $ tr $ do
let linkLogin = showRelURL Login
let linkHome = showRelURL MainPage
let linkNewGame = showRelURL $ GamesPage gn
td $ do
H.a "Nomyx: " ! (href $ toValue linkHome)
H.a ! A.id "gameButton" ! (href $ toValue linkNewGame) $ do
(fromString gn)
td ! A.style "text-align:right;" $ H.a ! (href $ toValue linkLogin) $ do
(fromString name)
img ! src "/static/pictures/person.png" ! A.style "vertical-align:middle;"
nomyxSite :: WebSession -> Site PlayerCommand (ServerPartT IO Response)
nomyxSite ws = setDefault MainPage $ mkSitePI $ (\a b -> evalStateT (runRouteT (catchRouteError . routedNomyxCommands) a b) ws)
routedNomyxCommands :: PlayerCommand -> RoutedNomyxServer Response
-- Authentication and login
routedNomyxCommands (Auth auth) = authenticate auth
routedNomyxCommands Login = loginPage
routedNomyxCommands Logout = logout
routedNomyxCommands ResetPassword = resetPasswordPage
routedNomyxCommands ChangePassword = changePasswordPanel
routedNomyxCommands OpenIdRealm = openIdRealmPanel
routedNomyxCommands PostAuth = postAuthenticate
-- Game menu
routedNomyxCommands (Menu tab game) = nomyxPage (Just game) tab
routedNomyxCommands MainPage = nomyxPage Nothing Home
-- Game management
routedNomyxCommands (JoinGame game) = joinGame game
routedNomyxCommands (LeaveGame game) = leaveGame game
routedNomyxCommands (DelGame game) = delGame game
routedNomyxCommands (GamesPage game) = newGamePage game
routedNomyxCommands SubmitNewGame = newGamePost
-- Game actions
routedNomyxCommands (DoInput is en game) = newInput' is en game
routedNomyxCommands (SubmitRule game) = submitRuleTemplatePost game
-- Templates
routedNomyxCommands (NewRuleTemplate game) = newRuleTemplate game
routedNomyxCommands (DelRuleTemplate game rn) = delRuleTemplate game rn
-- Modules
routedNomyxCommands (NewModule game) = newModule game
--Settings
routedNomyxCommands Advanced = advanced
routedNomyxCommands (SubmitPlayAs game) = newPlayAs game
routedNomyxCommands SubmitAdminPass = newAdminPass
routedNomyxCommands SubmitSettings = newSettings
routedNomyxCommands SaveFilePage = saveFilePage
-- Misc
routedNomyxCommands NomyxJS = ok $ toResponse nomyxJS
launchWebServer :: TVar Session -> Network -> IO ()
launchWebServer tv net = do
putStrLn $ "Starting web server...\nTo connect, drive your browser to \"" ++ nomyxURL net ++ "/Nomyx\""
s <- liftIO $ atomically $ readTVar tv
let set = _mSettings $ _multi s
let conf = nullConf {HS.port = T._port net}
docdir <- liftIO getDocDir
auth <- Auth.launchAuth (_saveDir set)
simpleHTTP conf $ server (WebSession tv auth) set net docdir
--serving Nomyx web page as well as data from this package and the language library package
server :: WebSession -> Settings -> Network -> String -> ServerPartT IO Response
server ws set net docdir = mconcat [
serveDirectory EnableBrowsing [] (_saveDir set),
serveDirectory EnableBrowsing [] docdir,
serveDirectory EnableBrowsing [] (_webDir set),
serveDirectory EnableBrowsing [] (_sourceDir set),
do decodeBody (defaultBodyPolicy "/tmp/" 102400 4096 4096)
html <- implSite (pack $ nomyxURL net) "/Nomyx" (nomyxSite ws)
return $ toResponse html]
catchRouteError :: RoutedNomyxServer Response -> RoutedNomyxServer Response
catchRouteError page = page `catchError` const backToLogin where
backToLogin :: RoutedNomyxServer Response
backToLogin = toResponse <$> seeOther (showRelURL Login) ("Redirecting..." :: String)
getDocDir :: IO FilePath
getDocDir = do
datadir <- getDataDir
let (as, _:bs) = break (== "share") $ splitDirectories datadir
return $ joinPath $ as ++ ["share", "doc"] ++ bs