module IHP.Controller.Redirect
( redirectTo
, redirectToPath
, redirectToUrl
, redirectToSeeOther
, redirectToPathSeeOther
, redirectToUrlSeeOther
, redirectBack
, redirectBackWithFallback
) where
import Prelude
import Data.Text (Text)
import Data.Maybe (fromMaybe)
import Data.String.Conversions (cs, convertString)
import qualified Network.Wai.Util
import Network.URI (parseURI, uriToString)
import IHP.Router.UrlGenerator (HasPath (pathTo))
import Network.HTTP.Types.Status
import qualified Network.Wai.Middleware.Approot as Approot
import IHP.ControllerSupport
redirectTo :: (?request :: Request, HasPath action) => action -> IO ()
redirectTo :: forall action.
(?request::Request, HasPath action) =>
action -> IO ()
redirectTo action
action = (?request::Request) => Text -> IO ()
Text -> IO ()
redirectToPath (action -> Text
forall controller. HasPath controller => controller -> Text
pathTo action
action)
{-# INLINABLE redirectTo #-}
redirectToSeeOther :: (?request :: Request, HasPath action) => action -> IO ()
redirectToSeeOther :: forall action.
(?request::Request, HasPath action) =>
action -> IO ()
redirectToSeeOther action
action = (?request::Request) => Text -> IO ()
Text -> IO ()
redirectToPathSeeOther (action -> Text
forall controller. HasPath controller => controller -> Text
pathTo action
action)
{-# INLINABLE redirectToSeeOther #-}
redirectToPath :: (?request :: Request) => Text -> IO ()
redirectToPath :: (?request::Request) => Text -> IO ()
redirectToPath Text
path = Text -> IO ()
redirectToUrl (ByteString -> Text
forall a b. ConvertibleStrings a b => a -> b
convertString ByteString
baseUrl Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
path)
where
baseUrl :: ByteString
baseUrl = Request -> ByteString
Approot.getApproot ?request::Request
Request
?request
{-# INLINABLE redirectToPath #-}
redirectToPathSeeOther :: (?request :: Request) => Text -> IO ()
redirectToPathSeeOther :: (?request::Request) => Text -> IO ()
redirectToPathSeeOther Text
path = Text -> IO ()
redirectToUrlSeeOther (ByteString -> Text
forall a b. ConvertibleStrings a b => a -> b
convertString ByteString
baseUrl Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
path)
where
baseUrl :: ByteString
baseUrl = Request -> ByteString
Approot.getApproot ?request::Request
Request
?request
{-# INLINABLE redirectToPathSeeOther #-}
redirectToUrl :: Text -> IO ()
redirectToUrl :: Text -> IO ()
redirectToUrl Text
url = do
let !parsedUrl :: URI
parsedUrl = URI -> Maybe URI -> URI
forall a. a -> Maybe a -> a
fromMaybe
([Char] -> URI
forall a. HasCallStack => [Char] -> a
error ([Char]
"redirectToPath: Unable to parse url: " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Text -> [Char]
forall a. Show a => a -> [Char]
show Text
url))
([Char] -> Maybe URI
parseURI (Text -> [Char]
forall a b. ConvertibleStrings a b => a -> b
cs Text
url))
let !redirectResponse :: Response
redirectResponse = Response -> Maybe Response -> Response
forall a. a -> Maybe a -> a
fromMaybe
([Char] -> Response
forall a. HasCallStack => [Char] -> a
error [Char]
"redirectToPath: Unable to construct redirect response")
(Status -> ResponseHeaders -> URI -> Maybe Response
Network.Wai.Util.redirect Status
status302 [] URI
parsedUrl)
Response -> IO ()
respondAndExit Response
redirectResponse
{-# INLINABLE redirectToUrl #-}
redirectToUrlSeeOther :: Text -> IO ()
redirectToUrlSeeOther :: Text -> IO ()
redirectToUrlSeeOther Text
url = do
let !parsedUrl :: URI
parsedUrl = URI -> Maybe URI -> URI
forall a. a -> Maybe a -> a
fromMaybe
([Char] -> URI
forall a. HasCallStack => [Char] -> a
error ([Char]
"redirectToUrlSeeOther: Unable to parse url: " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Text -> [Char]
forall a. Show a => a -> [Char]
show Text
url))
([Char] -> Maybe URI
parseURI (Text -> [Char]
forall a b. ConvertibleStrings a b => a -> b
cs Text
url))
let !redirectResponse :: Response
redirectResponse = Response -> Maybe Response -> Response
forall a. a -> Maybe a -> a
fromMaybe
([Char] -> Response
forall a. HasCallStack => [Char] -> a
error [Char]
"redirectToUrlSeeOther: Unable to construct redirect response")
(Status -> ResponseHeaders -> URI -> Maybe Response
Network.Wai.Util.redirect Status
status303 [] URI
parsedUrl)
Response -> IO ()
respondAndExit Response
redirectResponse
{-# INLINABLE redirectToUrlSeeOther #-}
redirectBack :: (?request :: Request) => IO ()
redirectBack :: (?request::Request) => IO ()
redirectBack = (?request::Request) => Text -> IO ()
Text -> IO ()
redirectBackWithFallback Text
"/"
{-# INLINABLE redirectBack #-}
redirectBackWithFallback :: (?request :: Request) => Text -> IO ()
redirectBackWithFallback :: (?request::Request) => Text -> IO ()
redirectBackWithFallback Text
fallbackPathOrUrl = do
case (?request::Request) => ByteString -> Maybe ByteString
ByteString -> Maybe ByteString
getHeader ByteString
"Referer" of
Just ByteString
referer -> case [Char] -> Maybe URI
parseURI (ByteString -> [Char]
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
referer) of
Just URI
uri -> Text -> IO ()
redirectToUrl ([Char] -> Text
forall a b. ConvertibleStrings a b => a -> b
cs (([Char] -> [Char]) -> URI -> [Char] -> [Char]
uriToString [Char] -> [Char]
forall a. a -> a
id URI
uri [Char]
""))
Maybe URI
Nothing -> (?request::Request) => Text -> IO ()
Text -> IO ()
redirectToPath (ByteString -> Text
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
referer)
Maybe ByteString
Nothing -> case [Char] -> Maybe URI
parseURI (Text -> [Char]
forall a b. ConvertibleStrings a b => a -> b
cs Text
fallbackPathOrUrl) of
Just URI
uri -> Text -> IO ()
redirectToUrl ([Char] -> Text
forall a b. ConvertibleStrings a b => a -> b
cs (([Char] -> [Char]) -> URI -> [Char] -> [Char]
uriToString [Char] -> [Char]
forall a. a -> a
id URI
uri [Char]
""))
Maybe URI
Nothing -> (?request::Request) => Text -> IO ()
Text -> IO ()
redirectToPath Text
fallbackPathOrUrl
{-# INLINABLE redirectBackWithFallback #-}