Skip to content

Commit a071f09

Browse files
committed
Merge branch 'master' of github.com:digitallyinduced/ihp
2 parents fca72a8 + a20a43f commit a071f09

File tree

3 files changed

+57
-3
lines changed

3 files changed

+57
-3
lines changed

Guide/controller.markdown

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,13 @@ When you need to pass a custom query parameter, you cannot use the [`redirectTo`
350350

351351
The redirect will use HTTP status code `302`. The [`baseUrl`](https://ihp.digitallyinduced.com/api-docs/IHP-FrameworkConfig.html#t:FrameworkConfig) in `Config/Config.hs` will be used. In development mode, the [`baseUrl`](https://ihp.digitallyinduced.com/api-docs/IHP-FrameworkConfig.html#t:FrameworkConfig) might not be specified in `Config/Config.hs`. Then it will be set to localhost by default.
352352

353+
If you need to force the follow-up request to be a `GET` (e.g. after a `POST` or `DELETE`), use [`redirectToSeeOther`](https://ihp.digitallyinduced.com/api-docs/IHP-Controller-Redirect.html#v:redirectToSeeOther) to send a 303 See Other:
354+
355+
```haskell
356+
action ExampleAction = do
357+
redirectToSeeOther ShowPostAction { postId = ... }
358+
```
359+
353360
### Redirect to a Path
354361

355362
Use [`redirectToPath`](https://ihp.digitallyinduced.com/api-docs/IHP-Controller-Redirect.html#v:redirectToPath) when you want to redirect to a path on the same domain:
@@ -366,6 +373,13 @@ action ExampleAction = do
366373
redirectToPath ((pathTo ShowPostAction { .. }) <> "&details=on")
367374
```
368375

376+
Use [`redirectToPathSeeOther`](https://ihp.digitallyinduced.com/api-docs/IHP-Controller-Redirect.html#v:redirectToPathSeeOther) to send a 303 redirect to a path:
377+
378+
```haskell
379+
action ExampleAction = do
380+
redirectToPathSeeOther "/blog/wp-login.php"
381+
```
382+
369383
### Redirect to a URL
370384

371385
Use [`redirectToUrl`](https://ihp.digitallyinduced.com/api-docs/IHP-Controller-Redirect.html#v:redirectToUrl) to redirect to some external URL:
@@ -375,6 +389,13 @@ action ExampleAction = do
375389
redirectToUrl "https://example.com/hello-world.html"
376390
```
377391

392+
Use [`redirectToUrlSeeOther`](https://ihp.digitallyinduced.com/api-docs/IHP-Controller-Redirect.html#v:redirectToUrlSeeOther) to send a 303 redirect to some external URL:
393+
394+
```haskell
395+
action ExampleAction = do
396+
redirectToUrlSeeOther "https://example.com/hello-world.html"
397+
```
398+
378399
## Action Execution
379400

380401
When calling a function to send the response, IHP will stop executing the action. Internally this is implemented by throwing and catching a [`ResponseException`](https://ihp.digitallyinduced.com/api-docs/src/IHP.ControllerSupport.html#ResponseException). Any code after e.g. a `render SomeView { .. }` call will not be called. This also applies to all redirect helpers.

ihp/IHP/AuthSupport/Controller/Sessions.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ newSessionAction :: forall record action.
3737
) => IO ()
3838
newSessionAction = do
3939
let alreadyLoggedIn = isJust (currentUserOrNothing @record)
40-
when alreadyLoggedIn (redirectToPath (afterLoginRedirectPath @record))
40+
when alreadyLoggedIn (redirectToPathSeeOther (afterLoginRedirectPath @record))
4141

4242
let user = newRecord @record
4343
render NewView { .. }
@@ -85,7 +85,7 @@ createSessionAction = do
8585
|> set #failedLoginAttempts 0
8686
|> updateRecord
8787
redirectUrl <- getSessionAndClear "IHP.LoginSupport.redirectAfterLogin"
88-
redirectToPath (fromMaybe (afterLoginRedirectPath @record) redirectUrl)
88+
redirectToPathSeeOther (fromMaybe (afterLoginRedirectPath @record) redirectUrl)
8989
else do
9090
setErrorMessage "Invalid Credentials"
9191
user :: record <- user
@@ -117,7 +117,7 @@ deleteSessionAction = do
117117
beforeLogout user
118118
logout user
119119
Nothing -> pure ()
120-
redirectToPath (afterLogoutRedirectPath @record)
120+
redirectToPathSeeOther (afterLogoutRedirectPath @record)
121121
{-# INLINE deleteSessionAction #-}
122122

123123
currentUserOrNothing :: forall user. (?context :: ControllerContext, HasNewSessionUrl user, Typeable user) => (Maybe user)

ihp/IHP/Controller/Redirect.hs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ module IHP.Controller.Redirect
77
( redirectTo
88
, redirectToPath
99
, redirectToUrl
10+
, redirectToSeeOther
11+
, redirectToPathSeeOther
12+
, redirectToUrlSeeOther
1013
, redirectBack
1114
, redirectBackWithFallback
1215
) where
@@ -33,6 +36,13 @@ redirectTo :: (?context :: ControllerContext, HasPath action) => action -> IO ()
3336
redirectTo action = redirectToPath (pathTo action)
3437
{-# INLINABLE redirectTo #-}
3538

39+
-- | Redirects to an action using HTTP 303 See Other
40+
--
41+
-- Forces the follow-up request to be a GET (useful after POST/DELETE).
42+
redirectToSeeOther :: (?context :: ControllerContext, HasPath action) => action -> IO ()
43+
redirectToSeeOther action = redirectToPathSeeOther (pathTo action)
44+
{-# INLINABLE redirectToSeeOther #-}
45+
3646
-- TODO: redirectTo user
3747

3848
-- | Redirects to a path (given as a string)
@@ -48,6 +58,15 @@ redirectToPath path = redirectToUrl (convertString baseUrl <> path)
4858
baseUrl = Approot.getApproot ?context.requestContext.request
4959
{-# INLINABLE redirectToPath #-}
5060

61+
-- | Redirects to a path using HTTP 303 See Other
62+
--
63+
-- Forces the follow-up request to be a GET (useful after POST/DELETE).
64+
redirectToPathSeeOther :: (?context :: ControllerContext) => Text -> IO ()
65+
redirectToPathSeeOther path = redirectToUrlSeeOther (convertString baseUrl <> path)
66+
where
67+
baseUrl = Approot.getApproot ?context.requestContext.request
68+
{-# INLINABLE redirectToPathSeeOther #-}
69+
5170
-- | Redirects to a url (given as a string)
5271
--
5372
-- __Example:__
@@ -67,6 +86,20 @@ redirectToUrl url = do
6786
respondAndExit redirectResponse
6887
{-# INLINABLE redirectToUrl #-}
6988

89+
-- | Redirects to a url using HTTP 303 See Other
90+
--
91+
-- Forces the follow-up request to be a GET (useful after POST/DELETE).
92+
redirectToUrlSeeOther :: (?context :: ControllerContext) => Text -> IO ()
93+
redirectToUrlSeeOther url = do
94+
let RequestContext { respond } = ?context.requestContext
95+
let !parsedUrl = fromMaybe
96+
(error ("redirectToUrlSeeOther: Unable to parse url: " <> show url))
97+
(parseURI (cs url))
98+
let !redirectResponse = fromMaybe
99+
(error "redirectToUrlSeeOther: Unable to construct redirect response")
100+
(Network.Wai.Util.redirect status303 [] parsedUrl)
101+
respondAndExit redirectResponse
102+
{-# INLINABLE redirectToUrlSeeOther #-}
70103

71104
-- | Redirects back to the last page
72105
--

0 commit comments

Comments
 (0)