Skip to content

Commit

Permalink
Approot
Browse files Browse the repository at this point in the history
  • Loading branch information
snoyberg committed Feb 9, 2012
1 parent a26ad23 commit 4dd9880
Show file tree
Hide file tree
Showing 15 changed files with 50 additions and 23 deletions.
2 changes: 2 additions & 0 deletions yesod-core/Yesod/Core.hs
Expand Up @@ -8,6 +8,8 @@ module Yesod.Core
-- ** Breadcrumbs
, YesodBreadcrumbs (..)
, breadcrumbs
-- * Types
, Approot (..)
-- * Utitlities
, maybeAuthorized
, widgetToPageContent
Expand Down
2 changes: 1 addition & 1 deletion yesod-core/Yesod/Dispatch.hs
Expand Up @@ -182,7 +182,7 @@ sendRedirect y segments' env =
, ("Location", Blaze.ByteString.Builder.toByteString dest')
] "Redirecting"
where
dest = joinPath y (approot y) segments' []
dest = joinPath y (resolveApproot y env) segments' []
dest' =
if S.null (W.rawQueryString env)
then dest
Expand Down
44 changes: 36 additions & 8 deletions yesod-core/Yesod/Internal/Core.hs
Expand Up @@ -28,6 +28,8 @@ module Yesod.Internal.Core
-- * Misc
, yesodVersion
, yesodRender
, resolveApproot
, Approot (..)
) where

import Yesod.Content
Expand Down Expand Up @@ -121,20 +123,36 @@ class YesodDispatch sub master where
-> W.Application
yesodRunner = defaultYesodRunner

-- | Define settings for a Yesod applications. The only required setting is
-- 'approot'; other than that, there are intelligent defaults.
-- | How to determine the root of the application for constructing URLs.
--
-- Note that future versions of Yesod may add new constructors without bumping
-- the major version number. As a result, you should /not/ pattern match on
-- @Approot@ values.
data Approot master = ApprootRelative -- ^ No application root.
| ApprootStatic Text
| ApprootMaster (master -> Text)
| ApprootRequest (master -> W.Request -> Text)

type ResolvedApproot = Text

-- | Define settings for a Yesod applications. All methods have intelligent
-- defaults, and therefore no implementation is required.
class RenderRoute a => Yesod a where
-- | An absolute URL to the root of the application. Do not include
-- trailing slash.
--
-- If you want to be lazy, you can supply an empty string under the
-- following conditions:
-- Default value: 'ApprootRelative'. This is valid under the following
-- conditions:
--
-- * Your application is served from the root of the domain.
--
-- * You do not use any features that require absolute URLs, such as Atom
-- feeds and XML sitemaps.
approot :: a -> Text
--
-- If this is not true, you should override with a different
-- implementation.
approot :: Approot a
approot = ApprootRelative

-- | The encryption key to be used for encrypting client sessions.
-- Returning 'Nothing' disables sessions.
Expand Down Expand Up @@ -395,7 +413,8 @@ defaultYesodRunner handler master sub murl toMasterRoute mkey req = do
handler
let sessionMap = Map.fromList
$ filter (\(x, _) -> x /= nonceKey) session'
yar <- handlerToYAR master sub toMasterRoute (yesodRender master) errorHandler rr murl sessionMap h
let ra = resolveApproot master req
yar <- handlerToYAR master sub toMasterRoute (yesodRender master ra) errorHandler rr murl sessionMap h
let mnonce = reqNonce rr
-- FIXME should we be caching this IV value and reusing it for efficiency?
iv <- {-# SCC "iv" #-} maybe (return $ error "Should not be used") (const $ liftIO CS.randomIV) mkey
Expand Down Expand Up @@ -633,14 +652,23 @@ ynHelper render scripts jscript jsLoc =

yesodRender :: Yesod y
=> y
-> ResolvedApproot
-> Route y
-> [(Text, Text)] -- ^ url query string
-> Text
yesodRender y url params =
yesodRender y ar url params =
TE.decodeUtf8 $ toByteString $
fromMaybe
(joinPath y (approot y) ps
(joinPath y ar ps
$ params ++ params')
(urlRenderOverride y url)
where
(ps, params') = renderRoute url

resolveApproot :: Yesod master => master -> W.Request -> ResolvedApproot
resolveApproot master req =
case approot of
ApprootRelative -> ""
ApprootStatic t -> t
ApprootMaster f -> f master
ApprootRequest f -> f master req
2 changes: 1 addition & 1 deletion yesod-core/test/YesodCoreTest/Cache.hs
Expand Up @@ -21,7 +21,7 @@ key2 = $(mkCacheKey)

mkYesod "C" [parseRoutes|/ RootR GET|]

instance Yesod C where approot _ = ""
instance Yesod C

getRootR :: Handler ()
getRootR = do
Expand Down
2 changes: 1 addition & 1 deletion yesod-core/test/YesodCoreTest/CleanPath.hs
Expand Up @@ -41,7 +41,7 @@ mkYesod "Y" [parseRoutes|
|]

instance Yesod Y where
approot _ = "http://test"
approot = ApprootStatic "http://test"
cleanPath _ s@("subsite":_) = Right s
cleanPath _ ["bar", ""] = Right ["bar"]
cleanPath _ ["bar"] = Left ["bar", ""]
Expand Down
2 changes: 1 addition & 1 deletion yesod-core/test/YesodCoreTest/ErrorHandling.hs
Expand Up @@ -21,7 +21,7 @@ mkYesod "App" [parseRoutes|
/after_runRequestBody AfterRunRequestBodyR POST
|]

instance Yesod App where approot _ = ""
instance Yesod App

getHomeR :: Handler RepHtml
getHomeR = defaultLayout $ toWidget [hamlet|
Expand Down
2 changes: 1 addition & 1 deletion yesod-core/test/YesodCoreTest/Exceptions.hs
Expand Up @@ -18,7 +18,7 @@ mkYesod "Y" [parseRoutes|
|]

instance Yesod Y where
approot _ = "http://test"
approot = ApprootStatic "http://test"
errorHandler (InternalError e) = return $ chooseRep $ RepPlain $ toContent e
errorHandler x = defaultErrorHandler x

Expand Down
3 changes: 1 addition & 2 deletions yesod-core/test/YesodCoreTest/Links.hs
Expand Up @@ -15,8 +15,7 @@ mkYesod "Y" [parseRoutes|
/ RootR GET
|]

instance Yesod Y where
approot _ = ""
instance Yesod Y

getRootR :: Handler RepHtml
getRootR = defaultLayout $ addHamlet [hamlet|<a href=@{RootR}>|]
Expand Down
1 change: 0 additions & 1 deletion yesod-core/test/YesodCoreTest/Media.hs
Expand Up @@ -15,7 +15,6 @@ import YesodCoreTest.MediaData
mkYesodDispatch "Y" resourcesY

instance Yesod Y where
approot _ = ""
addStaticContent _ _ content = do
tm <- getRouteToMaster
route <- getCurrentRoute
Expand Down
4 changes: 1 addition & 3 deletions yesod-core/test/YesodCoreTest/NoOverloadedStrings.hs
Expand Up @@ -8,7 +8,6 @@ import Test.Hspec.HUnit ()
import Yesod.Core hiding (Request)
import Network.Wai.Test
import Data.Monoid (mempty)
import Data.String (fromString)

data Subsite = Subsite

Expand All @@ -29,8 +28,7 @@ mkYesod "Y" [parseRoutes|
/subsite SubsiteR Subsite getSubsite
|]

instance Yesod Y where
approot _ = fromString ""
instance Yesod Y

getRootR :: Handler ()
getRootR = return ()
Expand Down
2 changes: 1 addition & 1 deletion yesod-core/test/YesodCoreTest/Redirect.hs
Expand Up @@ -13,7 +13,7 @@ mkYesod "Y" [parseRoutes|
/r307 R307 GET
/rregular RRegular GET
|]
instance Yesod Y where approot _ = "http://test"
instance Yesod Y where approot = ApprootStatic "http://test"
app :: Session () -> IO ()
app = yesod Y

Expand Down
2 changes: 1 addition & 1 deletion yesod-core/test/YesodCoreTest/Widget.hs
Expand Up @@ -28,7 +28,7 @@ mkYesod "Y" [parseRoutes|
|]

instance Yesod Y where
approot _ = "http://test"
approot = ApprootStatic "http://test"

getRootR :: Handler RepHtml
getRootR = defaultLayout $ toWidgetBody [julius|<not escaped>|]
Expand Down
1 change: 1 addition & 0 deletions yesod-core/test/YesodCoreTest/YesodTest.hs
Expand Up @@ -3,6 +3,7 @@ module YesodCoreTest.YesodTest
( yesod
, parseRoutes, mkYesod, yesodDispatch, renderRoute, Yesod(..)
, redirect
, Approot (..)
, module Network.Wai
, module Network.Wai.Test
, module Test.Hspec
Expand Down
2 changes: 1 addition & 1 deletion yesod/scaffold/Foundation.hs.cg
Expand Up @@ -83,7 +83,7 @@ type Form x = Html -> MForm ~sitearg~ ~sitearg~ (FormResult x, Widget)
-- Please see the documentation for the Yesod typeclass. There are a number
-- of settings which can be configured by overriding methods here.
instance Yesod ~sitearg~ where
approot = appRoot . settings
approot = ApprootMaster $ appRoot . settings

-- Place the session key file in the config folder
encryptKey _ = fmap Just $ getKey "config/client_session_key.aes"
Expand Down
2 changes: 1 addition & 1 deletion yesod/scaffold/tiny/Foundation.hs.cg
Expand Up @@ -60,7 +60,7 @@ mkYesodData "~sitearg~" $(parseRoutesFile "config/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 ~sitearg~ where
approot = appRoot . settings
approot = ApprootMaster $ appRoot . settings

-- Place the session key file in the config folder
encryptKey _ = fmap Just $ getKey "config/client_session_key.aes"
Expand Down

10 comments on commit 4dd9880

@dudebout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit broke the scaffolding:

Foundation.hs:86:15:
    Couldn't match expected type `Approot MyFoundation'
                with actual type `a0 -> c0'
    In the expression: appRoot . settings
    In an equation for `approot': approot = appRoot . settings
    In the instance declaration for `Yesod MyFoundation'

I installed the newest version after the version bump and for some reason the line about approot has not been updated to:

approot = ApprootMaster $ appRoot . settings

I can reproduce that with yesod init.
yesod version gives me 0.10.1

@snoyberg
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see: 4dd9880#L13R86

@dudebout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is where I found that line.
What I meant is that yesod init does give me approot = appRoot . settings instead of approot = ApprootMaster $ appRoot . settings

@snoyberg
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the code was updated. Did you install the new yesod executable?

@dudebout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I installed everything with the procedure described on the github front page.
The fact that yesod version gives me 0.10.1 does not imply that I have the latest executable?

I'll take a look.
Thanks for the prompt answer.

@snoyberg
Copy link
Member Author

@snoyberg snoyberg commented on 4dd9880 Feb 9, 2012 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dudebout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went into the yesod subfolder, cabal cleaned, then cabal install and it worked.
I don't understand why it was given that I was in a clean virthualenv.
Anyway. Thanks.

@gregwebs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without cabal cleaning, the build can produce surprising results. We support it in our build script with ./script/install --clean

@dudebout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a line in readme.md would help.
I knew about the dependency problems with cabal, but did not think of that clean.

@gregwebs
Copy link
Member

@gregwebs gregwebs commented on 4dd9880 Feb 10, 2012 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.