From 22f78dc47597207322f65d8700ca6aa3b5a5f217 Mon Sep 17 00:00:00 2001
From: Philippe PITTOLI <karchnu@karchnu.fr>
Date: Fri, 5 Apr 2024 18:23:01 +0200
Subject: [PATCH] Broader use of the Generic class.

---
 src/App/Container.purs                 | 31 ++++++++++++-----------
 src/App/Page/Navigation.purs           | 16 ++++++++----
 src/App/Page/Zone.purs                 | 30 +++++++----------------
 src/App/Type/AcceptedRRTypes.purs      |  4 +--
 src/App/Type/DKIM.purs                 | 34 +++++++++++++-------------
 src/App/Type/GenericSerialization.purs |  6 +++++
 src/App/Type/Pages.purs                |  9 +++++++
 7 files changed, 71 insertions(+), 59 deletions(-)
 create mode 100644 src/App/Type/GenericSerialization.purs

diff --git a/src/App/Container.purs b/src/App/Container.purs
index d0856d9..a16ce24 100644
--- a/src/App/Container.purs
+++ b/src/App/Container.purs
@@ -241,8 +241,7 @@ render state
   = HH.div_ $
     [ render_header
     , render_nav
-    , Bulma.columns_ [ Bulma.column_ [ render_login ]
-                     , Bulma.column_ [ render_notifications ] ]
+    , render_notifications
     , case state.current_page of
         Home           -> render_home
         Authentication -> render_auth_form
@@ -264,8 +263,6 @@ render state
         GoodNotification v -> Bulma.box [Bulma.notification_success v CloseNotif]
         BadNotification  v -> Bulma.box [Bulma.notification_danger  v CloseNotif]
 
-    render_login = maybe (Bulma.p "") (\l -> Bulma.box [ Bulma.p $ "You are connected as: " <> l]) state.login
-
     render_home :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad
     render_home = HH.slot_ _ho unit HomeInterface.component unit
     render_domainlist_interface :: forall monad. MonadAff monad => H.ComponentHTML Action ChildSlots monad
@@ -320,19 +317,21 @@ handleAction = case _ of
       Nothing -> revert_old_page
       Just _ -> pure unit -- Authentication will happen when web sockets are up!
 
+    login_name <- H.liftEffect $ Storage.getItem "user-login" sessionstorage
+    case login_name of
+      Nothing -> pure unit
+      Just name -> do H.modify_ _ { login = Just name }
+                      H.tell _nav unit $ NavigationInterface.TellLogin (Just name)
+
   Routing page -> do
     -- Store the current page we are on and restore it when we reload.
     sessionstorage <- H.liftEffect $ Window.sessionStorage =<< HTML.window
+    H.liftEffect $ Storage.setItem "current-page" (show page) sessionstorage
+
     _ <- case page of
-      Home           -> H.liftEffect $ Storage.setItem "current-page" "Home"           sessionstorage
-      Authentication -> H.liftEffect $ Storage.setItem "current-page" "Authentication" sessionstorage
-      Registration   -> H.liftEffect $ Storage.setItem "current-page" "Registration"   sessionstorage
-      MailValidation -> H.liftEffect $ Storage.setItem "current-page" "MailValidation" sessionstorage
-      DomainList     -> H.liftEffect $ Storage.setItem "current-page" "DomainList"     sessionstorage
-      Zone zone      -> do _ <- H.liftEffect $ Storage.setItem "current-page" "Zone"   sessionstorage
-                           H.liftEffect $ Storage.setItem      "current-zone" zone     sessionstorage
-      Setup          -> H.liftEffect $ Storage.setItem "current-page" "Setup"          sessionstorage
-      Administration -> H.liftEffect $ Storage.setItem "current-page" "Administration" sessionstorage
+      Zone zone  -> H.liftEffect $ Storage.setItem "current-zone" zone sessionstorage
+      _          -> pure unit
+
     H.modify_ _ { current_page = page }
 
   Log message -> do
@@ -403,7 +402,11 @@ handleAction = case _ of
 
     AI.AuthenticateToAuthd v  -> handleAction $ AuthenticateToAuthd (Right v)
     AI.Log message            -> handleAction $ Log message
-    AI.UserLogin login        -> H.modify_ _ { login = Just login }
+    AI.UserLogin login        -> do
+      sessionstorage <- H.liftEffect $ Window.sessionStorage =<< HTML.window
+      _ <- H.liftEffect $ Storage.setItem "user-login" login sessionstorage
+      H.modify_ _ { login = Just login }
+      H.tell _nav unit $ NavigationInterface.TellLogin (Just login)
 
   RegistrationInterfaceEvent ev -> case ev of
     RI.MessageToSend message  -> H.tell _ws_auth unit (WS.ToSend message)
diff --git a/src/App/Page/Navigation.purs b/src/App/Page/Navigation.purs
index 5d750ae..9fec7d3 100644
--- a/src/App/Page/Navigation.purs
+++ b/src/App/Page/Navigation.purs
@@ -34,6 +34,7 @@ data Output
 data Query a 
   = ToggleLogged Boolean a
   | ToggleAdmin Boolean a
+  | TellLogin (Maybe String) a
 
 type Slot = H.Slot Query Output
 
@@ -55,7 +56,7 @@ data Action
 -- | - `logged`, a boolean to toggle the display of some parts of the menu.
 -- | - `active`, a boolean to toggle the display of the menu.
 -- | - `admin`, a boolean to toggle the display of administration page link.
-type State = { logged :: Boolean, active :: Boolean, admin :: Boolean }
+type State = { logged :: Boolean, login :: Maybe String, active :: Boolean, admin :: Boolean }
 
 component :: forall m. MonadAff m => H.Component Query Input Output m
 component =
@@ -68,7 +69,7 @@ component =
     }
 
 initialState :: Input -> State
-initialState _ = { logged: false, active: false, admin: false }
+initialState _ = { logged: false, login: Nothing, active: false, admin: false }
 
 handleAction :: forall m. MonadAff m => Action -> H.HalogenM State Action () Output m Unit
 handleAction = case _ of
@@ -87,6 +88,9 @@ handleQuery = case _ of
   ToggleAdmin isadmin a -> do
     H.modify_ _ { admin = isadmin }
     pure (Just a)
+  TellLogin login a -> do
+    H.modify_ _ { login = login }
+    pure (Just a)
 
 
 -- | The navigation bar is a complex component to render.
@@ -98,7 +102,7 @@ handleQuery = case _ of
 -- | Also, when clicked again, the list disappears.
 
 render :: forall m. State -> H.ComponentHTML Action () m
-render { logged, active, admin } =
+render { logged, active, admin, login } =
   main_nav
     [ nav_brand [ logo, burger_menu ]
     , nav_menu
@@ -117,7 +121,7 @@ render { logged, active, admin } =
   right_bar_div =
     case logged of
         false -> [ link_auth, link_register, link_mail_validation ]
-        _     -> [ link_setup, link_disconnection ]
+        _     -> render_login login <> [ link_setup, link_disconnection ]
 
   navbar_color = C.is_success
 
@@ -127,7 +131,7 @@ render { logged, active, admin } =
            , ARIA.role "navigation"
            ]
 
-  logo = HH.strong [HP.classes $ C.navbar_item <> (C.is_size 4)] [HH.text "🔻🍉"]
+  logo = HH.strong [HP.classes $ C.navbar_item <> (C.is_size 4)] [HH.text "🍉"]
   --  HH.a [HP.classes C.navbar_item, HP.href "/"]
   --       [HH.img [HP.src "/logo.jpeg", HP.width 112, HP.height 28]]
 
@@ -158,6 +162,8 @@ render { logged, active, admin } =
   link_register        = nav_link_strong "Register"          (Navigate Registration)
   link_mail_validation = nav_link        "Mail verification" (Navigate MailValidation)
   link_setup           = nav_link_warn   "⚒ Setup"           (Navigate Setup)
+  render_login Nothing = []
+  render_login (Just l)= [nav_link       ("logged as " <> l) (Navigate Setup)]
   link_disconnection   =
     nav_link_ (C.has_text_light <> C.has_background_danger) "Disconnection" UnLog
 
diff --git a/src/App/Page/Zone.purs b/src/App/Page/Zone.purs
index 1ef95b9..433f7ab 100644
--- a/src/App/Page/Zone.purs
+++ b/src/App/Page/Zone.purs
@@ -189,18 +189,6 @@ data RRModal
   | UpdateRRModal
   | RemoveRRModal RRId
 
-show_accepted_type :: AcceptedRRTypes -> String
-show_accepted_type = case _ of
-  A     -> "A"
-  AAAA  -> "AAAA"
-  TXT   -> "TXT"
-  CNAME -> "CNAME"
-  NS    -> "NS"
-  MX    -> "MX"
-  SRV   -> "SRV"
-  SPF   -> "SPF"
-  DKIM  -> "DKIM"
-
 string_to_acceptedtype :: String -> Maybe AcceptedRRTypes
 string_to_acceptedtype str = case str of
   "A"     -> Just     A
@@ -506,12 +494,12 @@ render state
           , Bulma.div_content [Bulma.explanation Explanations.dkim_default_algorithms]
           , Bulma.selection_field "idDKIMSignature" "Signature algo"
               DKIM_sign_algo
-              (map DKIM.show_signature_algorithm DKIM.sign_algos)
-              (DKIM.show_signature_algorithm $ fromMaybe DKIM.RSA state.dkim.k)
+              (map show DKIM.sign_algos)
+              (show $ fromMaybe DKIM.RSA state.dkim.k)
           , Bulma.selection_field "idDKIMHash"      "Hash algo"
               DKIM_hash_algo
-              (map DKIM.show_hashing_algorithm DKIM.hash_algos)
-              (DKIM.show_hashing_algorithm   $ fromMaybe DKIM.SHA256 state.dkim.h)
+              (map show DKIM.hash_algos)
+              (show $ fromMaybe DKIM.SHA256 state.dkim.h)
           , Bulma.box_input "pkDKIM" "Public Key" "Your public key, such as 'MIIBIjANBgqh...'"
               DKIM_pubkey state.dkim.p should_be_disabled
           , Bulma.box_input "noteDKIM" "Note" "Note for fellow administrators."
@@ -535,7 +523,7 @@ render state
           where
           title = case state.rr_modal of
             NoModal             -> "Error: no modal should be displayed"
-            NewRRModal t_       -> "New " <> show_accepted_type t_ <> " resource record"
+            NewRRModal t_       -> "New " <> show t_ <> " resource record"
             UpdateRRModal       -> "Update RR " <> show state._currentRR.rrid
             RemoveRRModal rr_id -> "Error: should display removal modal instead (for RR " <> show rr_id <> ")"
           foot = foot_ <> [Bulma.cancel_button CancelModal]
@@ -922,10 +910,10 @@ render_resources records
           Just dkim ->
             [
             -- , HH.td_ [ Bulma.p $ maybe "(default)" id rr.v ] -- For now, version isn't displayed. Assume DKIM1.
-              HH.td_ [ Bulma.p $ maybe "" DKIM.show_hashing_algorithm    dkim.h ]
-            , HH.td_ [ Bulma.p $ maybe "" DKIM.show_signature_algorithm  dkim.k ]
-            , HH.td_ [ Bulma.p $ CP.take 5                               dkim.p ]
-            , HH.td_ [ Bulma.p $ fromMaybe ""                            dkim.n ]
+              HH.td_ [ Bulma.p $ maybe "" show dkim.h ]
+            , HH.td_ [ Bulma.p $ maybe "" show dkim.k ]
+            , HH.td_ [ Bulma.p $ CP.take 5     dkim.p ]
+            , HH.td_ [ Bulma.p $ fromMaybe ""  dkim.n ]
             , if rr.readonly
               then HH.td_ [ Bulma.btn_readonly ]
               else HH.td_ [ Bulma.btn_modify (CreateUpdateRRModal rr.rrid), Bulma.btn_delete (DeleteRRModal rr.rrid) ]
diff --git a/src/App/Type/AcceptedRRTypes.purs b/src/App/Type/AcceptedRRTypes.purs
index afcddc6..c524702 100644
--- a/src/App/Type/AcceptedRRTypes.purs
+++ b/src/App/Type/AcceptedRRTypes.purs
@@ -18,7 +18,7 @@ data AcceptedRRTypes
   | SPF
   | DKIM
 
-derive instance genericMyADT :: Generic AcceptedRRTypes _
+derive instance genericAcceptedRRTypes :: Generic AcceptedRRTypes _
 
-instance showMyADT :: Show AcceptedRRTypes where
+instance showAcceptedRRTypes :: Show AcceptedRRTypes where
   show = genericShow
diff --git a/src/App/Type/DKIM.purs b/src/App/Type/DKIM.purs
index 82d9fe9..6937674 100644
--- a/src/App/Type/DKIM.purs
+++ b/src/App/Type/DKIM.purs
@@ -1,5 +1,10 @@
 module App.Type.DKIM where
 
+import Prelude
+import Data.Generic.Rep (class Generic)
+import Data.Show.Generic (genericShow)
+
+import App.Type.GenericSerialization (generic_serialization)
 import Data.Maybe (Maybe(..))
 
 import Data.Codec.Argonaut (JsonCodec)
@@ -39,10 +44,13 @@ emptyDKIMRR = { v: Nothing, k: Just RSA, h: Just SHA256, p: "", n: Nothing }
 
 data HashingAlgorithm = {- SHA1 | -} SHA256
 hash_algos = [ {- "sha1", -} SHA256] :: Array HashingAlgorithm
+derive instance genericHashingAlgorithm :: Generic HashingAlgorithm _
+instance showHashingAlgorithm :: Show HashingAlgorithm where
+  show = genericShow
 
 -- | Codec for just encoding a single value of type `HashingAlgorithm`.
 codecHashingAlgorithm :: CA.JsonCodec HashingAlgorithm
-codecHashingAlgorithm = CA.prismaticCodec "HashingAlgorithm" str_to_hashing_algorithm show_hashing_algorithm CA.string
+codecHashingAlgorithm = CA.prismaticCodec "HashingAlgorithm" str_to_hashing_algorithm generic_serialization CA.string
 
 str_to_hashing_algorithm :: String -> Maybe HashingAlgorithm
 str_to_hashing_algorithm = case _ of
@@ -50,17 +58,15 @@ str_to_hashing_algorithm = case _ of
   "sha256"    -> Just SHA256
   _ -> Nothing
 
-show_hashing_algorithm :: HashingAlgorithm -> String
-show_hashing_algorithm = case _ of
-  -- SHA1   -> "sha1"
-  SHA256 -> "sha256"
-
 data SignatureAlgorithm = RSA | ED25519
 sign_algos = [RSA, ED25519] :: Array SignatureAlgorithm
+derive instance genericSignatureAlgorithm :: Generic SignatureAlgorithm _
+instance showSignatureAlgorithm :: Show SignatureAlgorithm where
+  show = genericShow
 
 -- | Codec for just encoding a single value of type `SignatureAlgorithm`.
 codecSignatureAlgorithm :: CA.JsonCodec SignatureAlgorithm
-codecSignatureAlgorithm = CA.prismaticCodec "SignatureAlgorithm" str_to_signature_algorithm show_signature_algorithm CA.string
+codecSignatureAlgorithm = CA.prismaticCodec "SignatureAlgorithm" str_to_signature_algorithm generic_serialization CA.string
 
 str_to_signature_algorithm :: String -> Maybe SignatureAlgorithm
 str_to_signature_algorithm = case _ of
@@ -68,22 +74,16 @@ str_to_signature_algorithm = case _ of
   "ed25519"   -> Just ED25519
   _ -> Nothing
 
-show_signature_algorithm :: SignatureAlgorithm -> String
-show_signature_algorithm = case _ of
-  RSA     -> "rsa"
-  ED25519 -> "ed25519"
-
 data Version = DKIM1
+derive instance genericVersion :: Generic Version _
+instance showVersion :: Show Version where
+  show = genericShow
 
 -- | Codec for just encoding a single value of type `Version`.
 codecVersion :: CA.JsonCodec Version
-codecVersion = CA.prismaticCodec "Version" str_to_version show_version CA.string
+codecVersion = CA.prismaticCodec "Version" str_to_version generic_serialization CA.string
 
 str_to_version :: String -> Maybe Version
 str_to_version = case _ of
   "dkim1"       -> Just DKIM1
   _ -> Nothing
-
-show_version :: Version -> String
-show_version = case _ of
-  DKIM1 -> "dkim1"
diff --git a/src/App/Type/GenericSerialization.purs b/src/App/Type/GenericSerialization.purs
new file mode 100644
index 0000000..7ede036
--- /dev/null
+++ b/src/App/Type/GenericSerialization.purs
@@ -0,0 +1,6 @@
+module App.Type.GenericSerialization where
+import Prelude (show, class Show, (<<<))
+import Data.String (toLower)
+
+generic_serialization :: forall a. Show a => a -> String
+generic_serialization = toLower <<< show
diff --git a/src/App/Type/Pages.purs b/src/App/Type/Pages.purs
index 7d85a29..d79fbaf 100644
--- a/src/App/Type/Pages.purs
+++ b/src/App/Type/Pages.purs
@@ -1,4 +1,8 @@
 module App.Type.Pages where
+
+import Prelude
+import Data.Generic.Rep (class Generic)
+import Data.Show.Generic (genericShow)
 -- | This list will grow in a near future.
 -- |
 -- | TODO: 
@@ -11,3 +15,8 @@ data Page
   | Zone String    -- | `Zone`: to manage a zone.
   | Setup          -- | `Setup`: user account administration page
   | Administration -- | `Administration`: administration page (for both `authd` and `dnsmanagerd`).
+
+derive instance genericPage :: Generic Page _
+
+instance showPage :: Show Page where
+  show = genericShow