-- | Generic response
module Mig.Core.Class.Response (
  Resp (..),
  RespOr (..),
  IsResp (..),
  badReq,
  internalServerError,
  notImplemented,
  redirect,
  setHeader,
  SetCookie (..),
  defCookie,
  setCookie,
) where

import Data.Bifunctor
import Data.ByteString (ByteString)
import Data.ByteString.Lazy qualified as BL
import Data.Kind
import Data.List qualified as List
import Data.Maybe
import Data.Text (Text)
import Data.Text qualified as Text
import Data.Text.Encoding qualified as Text
import Data.Time
import Network.HTTP.Media.RenderHeader (RenderHeader (..))
import Network.HTTP.Types.Header (HeaderName, ResponseHeaders, hSetCookie)
import Network.HTTP.Types.Status (Status, internalServerError500, notImplemented501, ok200, status302, status400)
import Web.HttpApiData
import Web.Internal.FormUrlEncoded

import Mig.Core.Class.MediaType (AnyMedia, MediaType, ToMediaType (..), ToRespBody (..))
import Mig.Core.Types.Http (Response, ResponseBody (..), noContentResponse)
import Mig.Core.Types.Http qualified as Response (Response (..))
import Mig.Core.Types.Http qualified as Types

-- | Response with info on the media-type encoded as type.
data Resp (media :: Type) a = Resp
  { forall media a. Resp media a -> Status
status :: Status
  -- ^ response status
  , forall media a. Resp media a -> ResponseHeaders
headers :: ResponseHeaders
  -- ^ response headers
  , forall media a. Resp media a -> Maybe a
body :: Maybe a
  -- ^ response body. Nothing means "no content" in the body
  }
  deriving (Int -> Resp media a -> ShowS
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall media a. Show a => Int -> Resp media a -> ShowS
forall media a. Show a => [Resp media a] -> ShowS
forall media a. Show a => Resp media a -> String
showList :: [Resp media a] -> ShowS
$cshowList :: forall media a. Show a => [Resp media a] -> ShowS
show :: Resp media a -> String
$cshow :: forall media a. Show a => Resp media a -> String
showsPrec :: Int -> Resp media a -> ShowS
$cshowsPrec :: forall media a. Show a => Int -> Resp media a -> ShowS
Show, Resp media a -> Resp media a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall media a. Eq a => Resp media a -> Resp media a -> Bool
/= :: Resp media a -> Resp media a -> Bool
$c/= :: forall media a. Eq a => Resp media a -> Resp media a -> Bool
== :: Resp media a -> Resp media a -> Bool
$c== :: forall media a. Eq a => Resp media a -> Resp media a -> Bool
Eq, forall a b. a -> Resp media b -> Resp media a
forall a b. (a -> b) -> Resp media a -> Resp media b
forall media a b. a -> Resp media b -> Resp media a
forall media a b. (a -> b) -> Resp media a -> Resp media b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> Resp media b -> Resp media a
$c<$ :: forall media a b. a -> Resp media b -> Resp media a
fmap :: forall a b. (a -> b) -> Resp media a -> Resp media b
$cfmap :: forall media a b. (a -> b) -> Resp media a -> Resp media b
Functor)

-- | Response that can contain an error. The error is represented with left case of an @Either@-type.
newtype RespOr ty err a = RespOr {forall ty err a.
RespOr ty err a -> Either (Resp ty err) (Resp ty a)
unRespOr :: Either (Resp ty err) (Resp ty a)}
  deriving (Int -> RespOr ty err a -> ShowS
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall ty err a.
(Show err, Show a) =>
Int -> RespOr ty err a -> ShowS
forall ty err a. (Show err, Show a) => [RespOr ty err a] -> ShowS
forall ty err a. (Show err, Show a) => RespOr ty err a -> String
showList :: [RespOr ty err a] -> ShowS
$cshowList :: forall ty err a. (Show err, Show a) => [RespOr ty err a] -> ShowS
show :: RespOr ty err a -> String
$cshow :: forall ty err a. (Show err, Show a) => RespOr ty err a -> String
showsPrec :: Int -> RespOr ty err a -> ShowS
$cshowsPrec :: forall ty err a.
(Show err, Show a) =>
Int -> RespOr ty err a -> ShowS
Show, RespOr ty err a -> RespOr ty err a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall ty err a.
(Eq err, Eq a) =>
RespOr ty err a -> RespOr ty err a -> Bool
/= :: RespOr ty err a -> RespOr ty err a -> Bool
$c/= :: forall ty err a.
(Eq err, Eq a) =>
RespOr ty err a -> RespOr ty err a -> Bool
== :: RespOr ty err a -> RespOr ty err a -> Bool
$c== :: forall ty err a.
(Eq err, Eq a) =>
RespOr ty err a -> RespOr ty err a -> Bool
Eq, forall a b. a -> RespOr ty err b -> RespOr ty err a
forall a b. (a -> b) -> RespOr ty err a -> RespOr ty err b
forall ty err a b. a -> RespOr ty err b -> RespOr ty err a
forall ty err a b. (a -> b) -> RespOr ty err a -> RespOr ty err b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> RespOr ty err b -> RespOr ty err a
$c<$ :: forall ty err a b. a -> RespOr ty err b -> RespOr ty err a
fmap :: forall a b. (a -> b) -> RespOr ty err a -> RespOr ty err b
$cfmap :: forall ty err a b. (a -> b) -> RespOr ty err a -> RespOr ty err b
Functor)

-------------------------------------------------------------------------------------
-- response class

{-| Values that can be converted to low-level response.

The repsonse value is usually one of two cases:

* @Resp a@ -- for routes which always produce a value

* @RespOr err a@ - for routes that can also produce an error or value.

* @Response@ - low-level HTTP-response.
-}
class IsResp a where
  -- | the type of response body value
  type RespBody a :: Type

  -- | the type of an error
  type RespError a :: Type

  -- | the media tpye of resp
  type RespMedia a :: Type

  -- | Returns valid repsonse with 200 status
  ok :: RespBody a -> a

  -- | Returns an error with given status
  bad :: Status -> RespError a -> a

  -- | response with no content
  noContent :: Status -> a

  -- | Add some header to the response
  addHeaders :: ResponseHeaders -> a -> a

  -- | Get response headers
  getHeaders :: a -> ResponseHeaders

  -- | Sets repsonse status
  setStatus :: Status -> a -> a

  -- | Get response body
  getRespBody :: a -> Maybe (RespBody a)

  -- | Get response error
  getRespError :: a -> Maybe (RespError a)

  -- | Get response status
  getStatus :: a -> Status

  -- | Set the media type of the response
  setMedia :: MediaType -> a -> a
  setMedia MediaType
media = forall a. IsResp a => ResponseHeaders -> a -> a
addHeaders [(HeaderName
"Content-Type", forall h. RenderHeader h => h -> ByteString
renderHeader MediaType
media)]

  -- | Reads the media type by response type
  getMedia :: MediaType

  -- | Converts value to low-level response
  toResponse :: a -> Response

-- | Set header for response
setHeader :: (IsResp a, ToHttpApiData h) => HeaderName -> h -> a -> a
setHeader :: forall a h.
(IsResp a, ToHttpApiData h) =>
HeaderName -> h -> a -> a
setHeader HeaderName
name h
val = forall a. IsResp a => ResponseHeaders -> a -> a
addHeaders [(HeaderName
name, forall a. ToHttpApiData a => a -> ByteString
toHeader h
val)]

instance (ToRespBody ty a) => IsResp (Resp ty a) where
  type RespBody (Resp ty a) = a
  type RespError (Resp ty a) = a
  type RespMedia (Resp ty a) = ty

  ok :: RespBody (Resp ty a) -> Resp ty a
ok = forall media a.
Status -> ResponseHeaders -> Maybe a -> Resp media a
Resp Status
ok200 [] forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just
  bad :: Status -> RespError (Resp ty a) -> Resp ty a
bad Status
status = forall media a.
Status -> ResponseHeaders -> Maybe a -> Resp media a
Resp Status
status [] forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just
  addHeaders :: ResponseHeaders -> Resp ty a -> Resp ty a
addHeaders ResponseHeaders
hs Resp ty a
x = Resp ty a
x{$sel:headers:Resp :: ResponseHeaders
headers = Resp ty a
x.headers forall a. Semigroup a => a -> a -> a
<> ResponseHeaders
hs}
  getHeaders :: Resp ty a -> ResponseHeaders
getHeaders Resp ty a
x = Resp ty a
x.headers
  noContent :: Status -> Resp ty a
noContent Status
st = forall media a.
Status -> ResponseHeaders -> Maybe a -> Resp media a
Resp Status
st [] forall a. Maybe a
Nothing
  setStatus :: Status -> Resp ty a -> Resp ty a
setStatus Status
st Resp ty a
x = Resp ty a
x{$sel:status:Resp :: Status
status = Status
st}
  getStatus :: Resp ty a -> Status
getStatus Resp ty a
x = Resp ty a
x.status
  getMedia :: MediaType
getMedia = forall {k} (a :: k). ToMediaType a => MediaType
toMediaType @ty
  getRespBody :: Resp ty a -> Maybe (RespBody (Resp ty a))
getRespBody Resp ty a
x = Resp ty a
x.body
  getRespError :: Resp ty a -> Maybe (RespError (Resp ty a))
getRespError Resp ty a
x
    | Resp ty a
x.status forall a. Eq a => a -> a -> Bool
== Status
ok200 = forall a. Maybe a
Nothing
    | Bool
otherwise = Resp ty a
x.body

  toResponse :: Resp ty a -> Response
toResponse Resp ty a
a = Status -> ResponseHeaders -> ResponseBody -> Response
Response.Response Resp ty a
a.status ResponseHeaders
headers ResponseBody
body
    where
      media :: MediaType
media = forall {k} (a :: k). ToMediaType a => MediaType
toMediaType @ty
      headers :: ResponseHeaders
headers = Resp ty a
a.headers forall a. Semigroup a => a -> a -> a
<> [(HeaderName
"Content-Type", forall h. RenderHeader h => h -> ByteString
renderHeader MediaType
media)]
      body :: ResponseBody
body = MediaType -> ByteString -> ResponseBody
RawResp MediaType
media (forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
"" (forall {k} (ty :: k) b. ToRespBody ty b => b -> ByteString
toRespBody @ty) Resp ty a
a.body)

instance IsResp Response where
  type RespBody Response = BL.ByteString
  type RespError Response = BL.ByteString
  type RespMedia Response = AnyMedia

  ok :: RespBody Response -> Response
ok = Status -> ResponseHeaders -> ResponseBody -> Response
Response.Response Status
ok200 [] forall b c a. (b -> c) -> (a -> b) -> a -> c
. MediaType -> ByteString -> ResponseBody
RawResp MediaType
"*/*"
  bad :: Status -> RespError Response -> Response
bad Status
st = Status -> ResponseHeaders -> ResponseBody -> Response
Response.Response Status
st [] forall b c a. (b -> c) -> (a -> b) -> a -> c
. MediaType -> ByteString -> ResponseBody
RawResp MediaType
"*/*"
  addHeaders :: ResponseHeaders -> Response -> Response
addHeaders ResponseHeaders
hs Response
x = Response
x{$sel:headers:Response :: ResponseHeaders
Response.headers = Response
x.headers forall a. Semigroup a => a -> a -> a
<> ResponseHeaders
hs}
  noContent :: Status -> Response
noContent = Status -> Response
noContentResponse
  setStatus :: Status -> Response -> Response
setStatus Status
st Response
x = Response
x{$sel:status:Response :: Status
Response.status = Status
st}
  getMedia :: MediaType
getMedia = MediaType
"*/*"
  getStatus :: Response -> Status
getStatus Response
x = Response
x.status
  getHeaders :: Response -> ResponseHeaders
getHeaders Response
x = Response
x.headers
  getRespBody :: Response -> Maybe (RespBody Response)
getRespBody Response
x = case Response
x.body of
    RawResp MediaType
_ ByteString
res -> forall a. a -> Maybe a
Just ByteString
res
    ResponseBody
_ -> forall a. Maybe a
Nothing
  getRespError :: Response -> Maybe (RespError Response)
getRespError Response
x
    | Response
x.status forall a. Eq a => a -> a -> Bool
== Status
ok200 = forall a. Maybe a
Nothing
    | Bool
otherwise = forall a. IsResp a => a -> Maybe (RespBody a)
getRespBody Response
x

  toResponse :: Response -> Response
toResponse = forall a. a -> a
id

  setMedia :: MediaType -> Response -> Response
setMedia MediaType
media = forall a. IsResp a => ResponseHeaders -> a -> a
addHeaders [(HeaderName
"Content-Type", forall h. RenderHeader h => h -> ByteString
renderHeader MediaType
media)] forall b c a. (b -> c) -> (a -> b) -> a -> c
. Response -> Response
updateBody
    where
      updateBody :: Response -> Response
updateBody Response
response = Response
response{$sel:body:Response :: ResponseBody
Response.body = ResponseBody -> ResponseBody
setBodyMedia Response
response.body}

      setBodyMedia :: ResponseBody -> ResponseBody
setBodyMedia = \case
        RawResp MediaType
_ ByteString
content -> MediaType -> ByteString -> ResponseBody
RawResp MediaType
media ByteString
content
        ResponseBody
other -> ResponseBody
other

instance (ToRespBody ty err, ToRespBody ty a) => IsResp (RespOr ty err a) where
  type RespBody (RespOr ty err a) = a
  type RespError (RespOr ty err a) = err
  type RespMedia (RespOr ty err a) = ty

  ok :: RespBody (RespOr ty err a) -> RespOr ty err a
ok = forall ty err a.
Either (Resp ty err) (Resp ty a) -> RespOr ty err a
RespOr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall media a.
Status -> ResponseHeaders -> Maybe a -> Resp media a
Resp Status
ok200 [] forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just
  bad :: Status -> RespError (RespOr ty err a) -> RespOr ty err a
bad Status
status = forall ty err a.
Either (Resp ty err) (Resp ty a) -> RespOr ty err a
RespOr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Either a b
Left forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IsResp a => Status -> RespError a -> a
bad Status
status
  addHeaders :: ResponseHeaders -> RespOr ty err a -> RespOr ty err a
addHeaders ResponseHeaders
hs = forall ty err a.
Either (Resp ty err) (Resp ty a) -> RespOr ty err a
RespOr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap (forall a. IsResp a => ResponseHeaders -> a -> a
addHeaders ResponseHeaders
hs) (forall a. IsResp a => ResponseHeaders -> a -> a
addHeaders ResponseHeaders
hs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ty err a.
RespOr ty err a -> Either (Resp ty err) (Resp ty a)
unRespOr
  noContent :: Status -> RespOr ty err a
noContent Status
st = forall ty err a.
Either (Resp ty err) (Resp ty a) -> RespOr ty err a
RespOr forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right (forall a. IsResp a => Status -> a
noContent Status
st)
  setStatus :: Status -> RespOr ty err a -> RespOr ty err a
setStatus Status
st = forall ty err a.
Either (Resp ty err) (Resp ty a) -> RespOr ty err a
RespOr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap (forall a. IsResp a => Status -> a -> a
setStatus Status
st) (forall a. IsResp a => Status -> a -> a
setStatus Status
st) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ty err a.
RespOr ty err a -> Either (Resp ty err) (Resp ty a)
unRespOr
  getMedia :: MediaType
getMedia = forall {k} (a :: k). ToMediaType a => MediaType
toMediaType @ty
  getStatus :: RespOr ty err a -> Status
getStatus (RespOr Either (Resp ty err) (Resp ty a)
x) = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (.status) (.status) Either (Resp ty err) (Resp ty a)
x
  getHeaders :: RespOr ty err a -> ResponseHeaders
getHeaders (RespOr Either (Resp ty err) (Resp ty a)
x) = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (.headers) (forall media a. Resp media a -> ResponseHeaders
headers) Either (Resp ty err) (Resp ty a)
x
  getRespBody :: RespOr ty err a -> Maybe (RespBody (RespOr ty err a))
getRespBody (RespOr Either (Resp ty err) (Resp ty a)
x) = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a b. a -> b -> a
const forall a. Maybe a
Nothing) (.body) Either (Resp ty err) (Resp ty a)
x
  getRespError :: RespOr ty err a -> Maybe (RespError (RespOr ty err a))
getRespError (RespOr Either (Resp ty err) (Resp ty a)
x) = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (.body) (forall a b. a -> b -> a
const forall a. Maybe a
Nothing) Either (Resp ty err) (Resp ty a)
x

  toResponse :: RespOr ty err a -> Response
toResponse = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall a. IsResp a => a -> Response
toResponse forall a. IsResp a => a -> Response
toResponse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ty err a.
RespOr ty err a -> Either (Resp ty err) (Resp ty a)
unRespOr

-- | Bad request. The @bad@ response with 400 status.
badReq :: (IsResp a) => RespError a -> a
badReq :: forall a. IsResp a => RespError a -> a
badReq = forall a. IsResp a => Status -> RespError a -> a
bad Status
status400

-- | Internal server error. The @bad@ response with 500 status.
internalServerError :: (IsResp a) => RespError a -> a
internalServerError :: forall a. IsResp a => RespError a -> a
internalServerError = forall a. IsResp a => Status -> RespError a -> a
bad Status
internalServerError500

-- | Not implemented route. The @bad@ response with 501 status.
notImplemented :: (IsResp a) => RespError a -> a
notImplemented :: forall a. IsResp a => RespError a -> a
notImplemented = forall a. IsResp a => Status -> RespError a -> a
bad Status
notImplemented501

-- | Redirect to url. It is @bad@ response with 302 status and set header of "Location" to a given URL.
redirect :: (IsResp a) => Text -> a
redirect :: forall a. IsResp a => Text -> a
redirect Text
url = forall a. IsResp a => ResponseHeaders -> a -> a
addHeaders [(HeaderName
"Location", Text -> ByteString
Text.encodeUtf8 Text
url)] forall a b. (a -> b) -> a -> b
$ forall a. IsResp a => Status -> a
noContent Status
status302

-- | Set cookie as http header from form url encoded value
setCookie :: (ToForm cookie, IsResp resp) => SetCookie cookie -> resp -> resp
setCookie :: forall cookie resp.
(ToForm cookie, IsResp resp) =>
SetCookie cookie -> resp -> resp
setCookie SetCookie cookie
cookie = forall a. IsResp a => ResponseHeaders -> a -> a
addHeaders [(HeaderName
hSetCookie, forall a. ToForm a => SetCookie a -> ByteString
renderSetCookie SetCookie cookie
cookie)]

{-| Set cookie params. For explanation see an article
<https://web.archive.org/web/20170122122852/https://www.nczonline.net/blog/2009/05/05/http-cookies-explained/>
-}
data SetCookie a = SetCookie
  { forall a. SetCookie a -> a
cookie :: a
  , forall a. SetCookie a -> Maybe UTCTime
expires :: Maybe UTCTime
  , forall a. SetCookie a -> Maybe Text
domain :: Maybe Text
  , forall a. SetCookie a -> Maybe Text
path :: Maybe Text
  , forall a. SetCookie a -> Bool
secure :: Bool
  , forall a. SetCookie a -> Bool
httpOnly :: Bool
  }
  deriving (Int -> SetCookie a -> ShowS
forall a. Show a => Int -> SetCookie a -> ShowS
forall a. Show a => [SetCookie a] -> ShowS
forall a. Show a => SetCookie a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SetCookie a] -> ShowS
$cshowList :: forall a. Show a => [SetCookie a] -> ShowS
show :: SetCookie a -> String
$cshow :: forall a. Show a => SetCookie a -> String
showsPrec :: Int -> SetCookie a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> SetCookie a -> ShowS
Show, SetCookie a -> SetCookie a -> Bool
forall a. Eq a => SetCookie a -> SetCookie a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SetCookie a -> SetCookie a -> Bool
$c/= :: forall a. Eq a => SetCookie a -> SetCookie a -> Bool
== :: SetCookie a -> SetCookie a -> Bool
$c== :: forall a. Eq a => SetCookie a -> SetCookie a -> Bool
Eq)

renderSetCookie :: (ToForm a) => SetCookie a -> ByteString
renderSetCookie :: forall a. ToForm a => SetCookie a -> ByteString
renderSetCookie SetCookie a
value =
  forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$
    (ByteString -> ByteString
BL.toStrict forall a b. (a -> b) -> a -> b
$ Form -> ByteString
urlEncodeForm forall a b. (a -> b) -> a -> b
$ forall a. ToForm a => a -> Form
toForm SetCookie a
value.cookie)
      forall a. a -> [a] -> [a]
: forall {a}. IsString a => [a] -> [a]
addColons
        ( forall a. [Maybe a] -> [a]
catMaybes
            [ Text -> Text -> ByteString
param Text
"expires" forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> Text
fmtTime forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SetCookie a
value.expires
            , Text -> Text -> ByteString
param Text
"domain" forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SetCookie a
value.domain
            , Text -> Text -> ByteString
param Text
"path" forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SetCookie a
value.path
            , forall {a}. a -> Bool -> Maybe a
flag ByteString
"secure" SetCookie a
value.secure
            , forall {a}. a -> Bool -> Maybe a
flag ByteString
"httpOnly" SetCookie a
value.httpOnly
            ]
        )
  where
    addColons :: [a] -> [a]
addColons [a]
xs
      | forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a]
xs = []
      | Bool
otherwise = a
";" forall a. a -> [a] -> [a]
: forall a. a -> [a] -> [a]
List.intersperse a
";" [a]
xs

    param :: Text -> Text -> ByteString
param Text
name Text
v = Text -> ByteString
Text.encodeUtf8 forall a b. (a -> b) -> a -> b
$ Text
name forall a. Semigroup a => a -> a -> a
<> Text
v

    flag :: a -> Bool -> Maybe a
flag a
name = \case
      Bool
True -> forall a. a -> Maybe a
Just a
name
      Bool
False -> forall a. Maybe a
Nothing

    fmtTime :: UTCTime -> Text
    fmtTime :: UTCTime -> Text
fmtTime = String -> Text
Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
expiresFormat

    expiresFormat :: String
    expiresFormat :: String
expiresFormat = String
"%a, %d-%b-%Y %X GMT"

-- | Default cookie which sets only the cookie itself.
defCookie :: a -> SetCookie a
defCookie :: forall a. a -> SetCookie a
defCookie a
val =
  SetCookie
    { $sel:cookie:SetCookie :: a
cookie = a
val
    , $sel:expires:SetCookie :: Maybe UTCTime
expires = forall a. Maybe a
Nothing
    , $sel:domain:SetCookie :: Maybe Text
domain = forall a. Maybe a
Nothing
    , $sel:path:SetCookie :: Maybe Text
path = forall a. Maybe a
Nothing
    , $sel:secure:SetCookie :: Bool
secure = Bool
False
    , $sel:httpOnly:SetCookie :: Bool
httpOnly = Bool
False
    }