Preliminary work for ownership management.

display
Philippe PITTOLI 2024-04-25 11:50:56 +02:00
parent b4a75feca0
commit 797f2ce248
3 changed files with 134 additions and 19 deletions

View File

@ -11,13 +11,13 @@
-- | - TODO: validate the domain before sending a message to `dnsmanagerd` -- | - TODO: validate the domain before sending a message to `dnsmanagerd`
module App.Page.DomainList where module App.Page.DomainList where
import Prelude (Unit, bind, discard, map, otherwise, pure, ($), (/=), (<<<), (<>), (>)) import Prelude (Unit, bind, discard, map, otherwise, pure, ($), (/=), (<<<), (<>), (>), (==))
import Data.Array as A import Data.Array as A
import Data.ArrayBuffer.Types (ArrayBuffer) import Data.ArrayBuffer.Types (ArrayBuffer)
import Data.Either (Either(..)) import Data.Either (Either(..))
import Data.String (toLower) import Data.String (toLower)
import Data.Maybe (Maybe(..), maybe) import Data.Maybe (Maybe(..), maybe, fromMaybe)
import Data.String.Utils (endsWith) import Data.String.Utils (endsWith)
import Effect.Aff.Class (class MonadAff) import Effect.Aff.Class (class MonadAff)
import Halogen as H import Halogen as H
@ -32,7 +32,9 @@ import App.DisplayErrors (error_to_paragraph_label)
import App.Validation.Label as Validation import App.Validation.Label as Validation
import App.Type.LogMessage import CSSClasses as C
import App.Type.DomainInfo
import App.Type.LogMessage (LogMessage(..))
import App.Message.DNSManagerDaemon as DNSManager import App.Message.DNSManagerDaemon as DNSManager
-- | `App.DomainListInterface` can send messages through websocket interface -- | `App.DomainListInterface` can send messages through websocket interface
@ -98,6 +100,8 @@ data Action
| AskDomainTransferAttempt Event | AskDomainTransferAttempt Event
| RemoveDomain String | RemoveDomain String
| EnterDomain String | EnterDomain String
| ShareDomain String
| UnshareDomain String
| DeleteDomainModal String | DeleteDomainModal String
| CancelModal | CancelModal
@ -127,7 +131,7 @@ type State =
{ newDomainForm :: NewDomainFormState { newDomainForm :: NewDomainFormState
, askDomainTransferForm :: AskDomainTransferState , askDomainTransferForm :: AskDomainTransferState
, accepted_domains :: Array String , accepted_domains :: Array String
, my_domains :: Array String , my_domains :: Array DomainInfo
, active_modal :: Maybe String , active_modal :: Maybe String
} }
@ -150,12 +154,21 @@ component =
default_domain :: String default_domain :: String
default_domain = "netlib.re" default_domain = "netlib.re"
debug_domains :: Array DomainInfo
debug_domains
= [ emptyDomainInfo { name = "test.example.com"
, share_key = Just "UUID"
, owners = ["myself", "you"] }
, emptyDomainInfo { name = "my-domain.example.com" }
, emptyDomainInfo { name = "my-other-domain.example.com" }
]
initialState :: Input -> State initialState :: Input -> State
initialState _ = initialState _ =
{ newDomainForm: { new_domain: "", _errors: [], selected_domain: default_domain } { newDomainForm: { new_domain: "", _errors: [], selected_domain: default_domain }
, askDomainTransferForm: { uuid: "", _errors: [] } , askDomainTransferForm: { uuid: "", _errors: [] }
, accepted_domains: [ default_domain ] , accepted_domains: [ default_domain ]
, my_domains: [ ] , my_domains: debug_domains
, active_modal: Nothing , active_modal: Nothing
} }
@ -166,16 +179,41 @@ render { accepted_domains, my_domains, newDomainForm, askDomainTransferForm, act
Nothing -> Bulma.columns_ Nothing -> Bulma.columns_
[ Bulma.column_ [ Bulma.h3 "New domain", render_add_domain_form [ Bulma.column_ [ Bulma.h3 "New domain", render_add_domain_form
, Bulma.hr , Bulma.hr
, Bulma.h3 "Ask for a domain transfer" , Bulma.h3 "Get the ownership of a domain"
, Bulma.simple_quote """ , Bulma.simple_quote """
Someone wants to give you the ownership of a domain. Someone wants to give you (or share with you) the ownership of a domain.
Please enter the UUID of the transfer. Please enter the UUID of the transfer.
""" """
, render_ask_domain_transfer_form , render_ask_domain_transfer_form
, Bulma.hr
, Bulma.h3 "Share the ownership of a domain"
, Bulma.simple_quote """
Ask for a "share token" for your domain and give it to other users.
All the owners be able to make modifications to the domain.
"""
, Bulma.hr
, Bulma.h3 "Transfer the ownership of a domain"
, Bulma.simple_quote """
Ask for a transfer token for your domain and give it to the new owner.
"""
] ]
, Bulma.column_ [ Bulma.h3 "My domains" , Bulma.column_ [ Bulma.h3 "My domains"
, if A.length my_domains > 0 , Bulma.simple_quote "You are the exclusive owner of the following domains."
then HH.ul_ $ map (\domain -> HH.li_ (domain_buttons domain)) $ A.sort my_domains , if A.length domains_i_exclusively_own > 0
then Bulma.table [] [ Bulma.table_header_owned_domains
, HH.tbody_ $ map owned_domain_row domains_i_exclusively_own
]
else Bulma.p "No domain yet."
, Bulma.hr
, Bulma.h3 "Shared domains"
, Bulma.simple_quote """
The following domains are shared with other users.
In case you are the last owner, you can "unshare" it and gain exclusive ownership.
"""
, if A.length domains_i_share > 0
then Bulma.table [] [ Bulma.table_header_shared_domains
, HH.tbody_ $ map shared_domain_row domains_i_share
]
else Bulma.p "No domain yet." else Bulma.p "No domain yet."
] ]
] ]
@ -185,6 +223,12 @@ render { accepted_domains, my_domains, newDomainForm, askDomainTransferForm, act
where where
modal_delete_button domain = Bulma.alert_btn "Delete the domain" (RemoveDomain domain) modal_delete_button domain = Bulma.alert_btn "Delete the domain" (RemoveDomain domain)
modal_cancel_button = Bulma.cancel_button CancelModal modal_cancel_button = Bulma.cancel_button CancelModal
-- I own all domain without a "share key".
domains_i_exclusively_own = A.sort $ A.filter (\domain -> domain.share_key == Nothing) my_domains
-- Shared domains are all domains with a share_key.
domains_i_share = A.sort $ A.filter (\domain -> domain.share_key /= Nothing) my_domains
warning_message domain warning_message domain
= HH.p [] [ HH.text $ "You are about to delete your domain \"" = HH.p [] [ HH.text $ "You are about to delete your domain \""
<> domain <> domain
@ -193,10 +237,20 @@ render { accepted_domains, my_domains, newDomainForm, askDomainTransferForm, act
, HH.text "." , HH.text "."
] ]
domain_buttons domain shared_domain_row domain = HH.tr_
= [ Bulma.alert_btn "delete" (DeleteDomainModal domain) [ HH.td_ [ Bulma.btn domain.name (EnterDomain domain.name) ]
, Bulma.btn domain (EnterDomain domain) , HH.td_ [ HH.text $ fromMaybe "" domain.share_key ]
] , if A.length domain.owners == 1
then Bulma.alert_btn "Unshare" (UnshareDomain domain.name)
else Bulma.btn_ro (C.is_warning) "Cannot unshare it"
]
owned_domain_row domain = HH.tr_
[ HH.td_ [ Bulma.btn domain.name (EnterDomain domain.name) ]
, HH.td_ [ Bulma.btn_ro (C.is_warning) "Share" ]
-- , Bulma.btn "Share" (ShareDomain domain.name)
, Bulma.alert_btn "Delete" (DeleteDomainModal domain.name)
]
render_add_domain_form = HH.form render_add_domain_form = HH.form
[ HE.onSubmit NewDomainAttempt ] [ HE.onSubmit NewDomainAttempt ]
@ -242,7 +296,9 @@ handleAction = case _ of
H.modify_ _ { accepted_domains = domains } H.modify_ _ { accepted_domains = domains }
UpdateMyDomains domains -> do UpdateMyDomains domains -> do
H.modify_ _ { my_domains = domains } H.raise $ Log $ SystemLog "TODO: update my domains."
-- TODO
-- H.modify_ _ { my_domains = domains }
HandleNewDomainInput adduserinp -> do HandleNewDomainInput adduserinp -> do
case adduserinp of case adduserinp of
@ -261,6 +317,12 @@ handleAction = case _ of
EnterDomain domain -> do EnterDomain domain -> do
H.raise $ ChangePageZoneInterface domain H.raise $ ChangePageZoneInterface domain
ShareDomain domain -> do
H.raise $ Log $ SystemLog $ "TODO: Share domain " <> domain
UnshareDomain domain -> do
H.raise $ Log $ SystemLog $ "TODO: Unshare domain " <> domain
DeleteDomainModal domain -> do DeleteDomainModal domain -> do
H.modify_ _ { active_modal = Just domain } H.modify_ _ { active_modal = Just domain }
@ -325,11 +387,14 @@ handleQuery = case _ of
handleAction $ UpdateAcceptedDomains response.accepted_domains handleAction $ UpdateAcceptedDomains response.accepted_domains
handleAction $ UpdateMyDomains response.my_domains handleAction $ UpdateMyDomains response.my_domains
(DNSManager.MkDomainAdded response) -> do (DNSManager.MkDomainAdded response) -> do
{ my_domains } <- H.get -- TODO
handleAction $ UpdateMyDomains (my_domains <> [response.domain]) H.raise $ Log $ SystemLog "TODO: domain added: update my domains."
--{ my_domains } <- H.get
--handleAction $ UpdateMyDomains (my_domains <> [response.domain])
(DNSManager.MkDomainDeleted response) -> do (DNSManager.MkDomainDeleted response) -> do
{ my_domains } <- H.get H.raise $ Log $ SystemLog "TODO: domain deleted: update my domains."
handleAction $ UpdateMyDomains $ A.filter ((/=) response.domain) my_domains --{ my_domains } <- H.get
--handleAction $ UpdateMyDomains $ A.filter ((/=) response.domain) my_domains
_ -> H.raise $ Log $ ErrorLog $ "Message not handled in DomainListInterface." _ -> H.raise $ Log $ ErrorLog $ "Message not handled in DomainListInterface."
pure (Just a) pure (Just a)
@ -338,7 +403,8 @@ page_reload s1 message =
case message of case message of
DNSManager.MkLogged response -> DNSManager.MkLogged response ->
s1 { accepted_domains = response.accepted_domains s1 { accepted_domains = response.accepted_domains
, my_domains = A.sort response.my_domains -- TODO
-- , my_domains = A.sort response.my_domains
} }
_ -> s1 _ -> s1

View File

@ -0,0 +1,33 @@
module App.Type.DomainInfo where
import Prelude ((<>), map, bind, pure)
import Data.Maybe (Maybe(..), maybe)
import Data.Codec.Argonaut (JsonCodec)
import Data.Codec.Argonaut as CA
import Data.Codec.Argonaut.Record as CAR
type DomainInfo
= { name :: String
, share_key :: Maybe String
, transfer_key :: Maybe String
, owners :: Array String
}
codec :: JsonCodec DomainInfo
codec = CA.object "DomainInfo"
(CAR.record
{ name: CA.string
, share_key: CAR.optional CA.string
, transfer_key: CAR.optional CA.string
, owners: CA.array CA.string
})
emptyDomainInfo :: DomainInfo
emptyDomainInfo
= { name: ""
, share_key: Nothing
, transfer_key: Nothing
, owners: []
}

View File

@ -61,6 +61,22 @@ table prop xs = HH.table ([ HP.classes $ C.table ] <> prop) xs
table_ :: forall w i. Array HH.ClassName -> HH.Node DHI.HTMLtable w i table_ :: forall w i. Array HH.ClassName -> HH.Node DHI.HTMLtable w i
table_ classes prop xs = HH.table ([ HP.classes $ C.table <> classes] <> prop) xs table_ classes prop xs = HH.table ([ HP.classes $ C.table <> classes] <> prop) xs
table_header_owned_domains :: forall w i. HH.HTML w i
table_header_owned_domains
= HH.thead_ [ HH.tr_ [ HH.th_ [ HH.text "Name" ]
, HH.th_ [ HH.text "" ]
, HH.th_ [ HH.text "" ]
]
]
table_header_shared_domains :: forall w i. HH.HTML w i
table_header_shared_domains
= HH.thead_ [ HH.tr_ [ HH.th_ [ HH.text "Name" ]
, HH.th_ [ HH.text "Share key" ]
, HH.th_ [ HH.text "" ]
]
]
mechanism_table_header :: forall w i. HH.HTML w i mechanism_table_header :: forall w i. HH.HTML w i
mechanism_table_header mechanism_table_header
= HH.thead_ [ HH.tr_ [ HH.th_ [ HH.text "Policy" ] = HH.thead_ [ HH.tr_ [ HH.th_ [ HH.text "Policy" ]