packages feed

hyperbole-0.4.2: src/Web/Hyperbole/Data/Session.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DefaultSignatures #-}

module Web.Hyperbole.Data.Session where

import Data.Map.Strict (Map)
import Data.Map.Strict qualified as M
import Data.String.Conversions (cs)
import Data.Text (Text)
import GHC.Generics
import Web.Hyperbole.Data.QueryData (Param (..), ParamValue (..), ToParam (..))
import Web.View.Types.Url (Segment)


data Cookie = Cookie
  { key :: Param
  , value :: Maybe ParamValue
  , path :: Maybe [Segment]
  }
  deriving (Show, Eq)
newtype Cookies = Cookies (Map Param Cookie)
  deriving newtype (Monoid, Semigroup, Show, Eq)


insert :: Cookie -> Cookies -> Cookies
insert cookie (Cookies m) =
  Cookies $ M.insert cookie.key cookie m


delete :: Param -> Cookies -> Cookies
delete key (Cookies m) =
  Cookies $ M.delete key m



lookup :: Param -> Cookies -> Maybe ParamValue
lookup key (Cookies m) = do
  cook <- M.lookup key m
  cook.value


deletedCookie :: forall a. (Session a) => Cookie
deletedCookie =
  Cookie (sessionKey @a) Nothing (cookiePath @a)


sessionCookie :: forall a. (Session a, ToParam a) => a -> Cookie
sessionCookie a = Cookie (sessionKey @a) (Just $ toParam a) (cookiePath @a)


fromList :: [Cookie] -> Cookies
fromList cks = Cookies $ M.fromList (fmap keyValue cks)
 where
  keyValue c = (c.key, c)


toList :: Cookies -> [Cookie]
toList (Cookies m) = M.elems m


{- | Configure a data type to persist in the 'session'

@
#EMBED Example/Docs/Sessions.hs data Preferences

#EMBED Example/Docs/Sessions.hs instance DefaultParam Preferences
@
-}
class Session a where
  -- | Unique key for the Session. Defaults to the datatypeName
  sessionKey :: Param
  default sessionKey :: (Generic a, GDatatypeName (Rep a)) => Param
  sessionKey = Param $ gDatatypeName $ from (undefined :: a)


  -- | By default Sessions are persisted only to the current page. Set this to `Just []` to make an application-wide Session
  cookiePath :: Maybe [Segment]
  default cookiePath :: Maybe [Segment]
  cookiePath = Nothing


-- | generic datatype name
class GDatatypeName f where
  gDatatypeName :: f p -> Text


instance (Datatype d) => GDatatypeName (M1 D d f) where
  gDatatypeName _ =
    cs $ datatypeName (undefined :: M1 D d f p)