2023-07-09 05:14:29 +02:00
|
|
|
-- | `App.ZoneInterface` provides an interface to display and modify a DNS zone.
|
|
|
|
-- |
|
|
|
|
-- | This interface allows to:
|
|
|
|
-- | - TODO: display all resource records of a zone
|
|
|
|
-- | - TODO: add new resource records
|
|
|
|
-- | - TODO: remove resource records
|
|
|
|
-- | - TODO: ask for confirmation on deletion
|
|
|
|
|
|
|
|
module App.ZoneInterface where
|
|
|
|
|
2023-07-10 20:33:28 +02:00
|
|
|
import Prelude (Unit, bind, comparing, discard, map, max, otherwise, pure, show, ($), (+), (/=), (<<<), (<>), (==))
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
import Data.Array as A
|
2023-07-11 02:00:29 +02:00
|
|
|
import Data.Int (fromString)
|
2023-07-09 05:14:29 +02:00
|
|
|
import Data.ArrayBuffer.Types (ArrayBuffer)
|
2023-07-10 20:33:28 +02:00
|
|
|
import Data.Array.NonEmpty as NonEmpty
|
2023-07-09 05:14:29 +02:00
|
|
|
import Data.Either (Either(..))
|
2023-07-10 20:33:28 +02:00
|
|
|
import Data.Foldable as Foldable
|
|
|
|
import Data.Maybe (Maybe(..), fromMaybe)
|
|
|
|
import Data.String.Regex as Regex
|
|
|
|
import Data.String.Regex.Flags as RegexFlags
|
|
|
|
import Data.String.Regex.Unsafe as RegexUnsafe
|
2023-07-09 05:14:29 +02:00
|
|
|
import Effect.Aff.Class (class MonadAff)
|
|
|
|
import Halogen as H
|
|
|
|
import Halogen.HTML as HH
|
|
|
|
import Halogen.HTML.Events as HE
|
|
|
|
import Halogen.HTML.Properties as HP
|
2023-07-10 20:33:28 +02:00
|
|
|
--import Web.Event.Event as Event
|
|
|
|
--import Web.Event.Event (Event)
|
|
|
|
|
2023-07-09 05:14:29 +02:00
|
|
|
import Bulma as Bulma
|
|
|
|
import CSSClasses as C
|
|
|
|
|
|
|
|
import App.RR
|
2023-07-11 03:26:42 +02:00
|
|
|
import App.ResourceRecord
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-10 20:33:28 +02:00
|
|
|
import App.LogMessage (LogMessage(..))
|
2023-07-09 05:14:29 +02:00
|
|
|
import App.Messages.DNSManagerDaemon as DNSManager
|
|
|
|
|
|
|
|
-- | `App.ZoneInterface` can send messages through websocket interface
|
|
|
|
-- | connected to dnsmanagerd. See `App.WS`.
|
|
|
|
-- |
|
|
|
|
-- | Also, this component can log messages and ask its parent (`App.Container`) to
|
|
|
|
-- | reconnect the websocket to `dnsmanagerd`.
|
|
|
|
|
|
|
|
data Output
|
|
|
|
= MessageToSend ArrayBuffer
|
|
|
|
| Log LogMessage
|
|
|
|
| DNSManagerReconnect
|
|
|
|
|
|
|
|
-- | `App.ZoneInterface` can receive messages from `dnsmanagerd`.
|
|
|
|
-- |
|
|
|
|
-- | The component is also informed when the connection is lost or up again.
|
|
|
|
|
|
|
|
data Query a
|
|
|
|
= MessageReceived ArrayBuffer a
|
|
|
|
| ConnectionIsDown a
|
|
|
|
| ConnectionIsUp a
|
|
|
|
|
|
|
|
type Slot = H.Slot Query Output
|
|
|
|
|
|
|
|
-- | `App.ZoneInterface` has a single input: the domain name.
|
|
|
|
|
|
|
|
type Input = String
|
|
|
|
|
|
|
|
-- | Possible component's actions are:
|
|
|
|
-- | - TODO: update the list of resource records
|
|
|
|
-- | - TODO: add a resource record
|
|
|
|
-- | - TODO: modify a resource record
|
|
|
|
-- | - TODO: remove a resource record
|
|
|
|
-- | - TODO: handle user inputs
|
|
|
|
|
2023-07-09 17:37:49 +02:00
|
|
|
data Update_SRR_Form
|
|
|
|
= Update_SRR_Type Int
|
|
|
|
| Update_SRR_Domain RecordDomain
|
|
|
|
| Update_SRR_TTL TTL
|
|
|
|
| Update_SRR_Value RecordValue
|
|
|
|
|
|
|
|
data Update_MX_Form
|
|
|
|
= Update_MX_Domain RecordDomain
|
|
|
|
| Update_MX_TTL TTL
|
|
|
|
| Update_MX_Value RecordValue
|
|
|
|
| Update_MX_Priority Priority
|
|
|
|
|
|
|
|
data Update_SRV_Form
|
|
|
|
= Update_SRV_Domain RecordDomain
|
|
|
|
| Update_SRV_TTL TTL
|
|
|
|
| Update_SRV_Value RecordValue
|
|
|
|
| Update_SRV_Priority Priority
|
|
|
|
| Update_SRV_Weight Weight
|
|
|
|
| Update_SRV_Port Port
|
2023-07-09 16:00:36 +02:00
|
|
|
|
2023-07-09 05:14:29 +02:00
|
|
|
data Action
|
2023-07-11 02:00:29 +02:00
|
|
|
= DeleteRRModal RRId
|
2023-07-09 05:14:29 +02:00
|
|
|
| CancelModal
|
|
|
|
|
|
|
|
| Initialize
|
|
|
|
| Finalize
|
|
|
|
|
|
|
|
-- New entries.
|
2023-07-09 17:37:49 +02:00
|
|
|
| UpdateNewSRRForm Update_SRR_Form
|
|
|
|
| UpdateNewMXForm Update_MX_Form
|
|
|
|
| UpdateNewSRVForm Update_SRV_Form
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-09 16:00:36 +02:00
|
|
|
-- Add new entries.
|
2023-07-09 17:37:49 +02:00
|
|
|
| AddSRR
|
2023-07-09 05:14:29 +02:00
|
|
|
| AddMX
|
|
|
|
| AddSRV
|
|
|
|
|
|
|
|
-- Entry already in our zone.
|
2023-07-11 02:00:29 +02:00
|
|
|
| UpdateLocalSRRForm RRId Update_SRR_Form
|
|
|
|
| UpdateLocalMXForm RRId Update_MX_Form
|
|
|
|
| UpdateLocalSRVForm RRId Update_SRV_Form
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-09 17:37:49 +02:00
|
|
|
| SyncRR RRId
|
2023-07-11 02:00:29 +02:00
|
|
|
| RemoveRR RRId
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
| TellSomethingWentWrong RRId String
|
|
|
|
|
|
|
|
-- |
|
|
|
|
|
|
|
|
type State =
|
|
|
|
{ _current_domain :: RecordDomain
|
2023-07-09 17:37:49 +02:00
|
|
|
, _srr :: Array (SimpleRR ())
|
2023-07-09 05:14:29 +02:00
|
|
|
, _mxrr :: Array (MXRR ())
|
|
|
|
, _srvrr :: Array (SRVRR ())
|
|
|
|
, _current_entry :: (SimpleRR ())
|
|
|
|
, _current_entry_mx :: (MXRR ())
|
|
|
|
, _current_entry_srv :: (SRVRR ())
|
|
|
|
|
|
|
|
, wsUp :: Boolean
|
2023-07-10 03:59:44 +02:00
|
|
|
, active_modal :: Maybe Int
|
2023-07-09 05:14:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
component :: forall m. MonadAff m => H.Component Query Input Output m
|
|
|
|
component =
|
|
|
|
H.mkComponent
|
|
|
|
{ initialState
|
|
|
|
, render
|
|
|
|
, eval: H.mkEval $ H.defaultEval
|
|
|
|
{ initialize = Just Initialize
|
|
|
|
, handleAction = handleAction
|
|
|
|
, handleQuery = handleQuery
|
|
|
|
, finalize = Just Finalize
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
-- | Default available domain: netlib.re.
|
|
|
|
|
|
|
|
default_domain :: String
|
|
|
|
default_domain = "netlib.re"
|
|
|
|
|
|
|
|
initialState :: Input -> State
|
2023-07-09 14:26:47 +02:00
|
|
|
initialState domain =
|
2023-07-09 05:14:29 +02:00
|
|
|
{ wsUp: true
|
|
|
|
, active_modal: Nothing
|
|
|
|
|
2023-07-09 14:26:47 +02:00
|
|
|
, _current_domain: domain
|
2023-07-10 20:15:22 +02:00
|
|
|
, _srr: []
|
|
|
|
, _mxrr: []
|
2023-07-09 05:14:29 +02:00
|
|
|
, _srvrr: []
|
|
|
|
, _current_entry: defaultResourceA
|
|
|
|
, _current_entry_mx: defaultResourceMX
|
|
|
|
, _current_entry_srv: defaultResourceSRV
|
|
|
|
}
|
|
|
|
|
|
|
|
render :: forall m. State -> H.ComponentHTML Action () m
|
|
|
|
render state
|
|
|
|
= Bulma.section_small
|
|
|
|
[ case state.wsUp, state.active_modal of
|
|
|
|
false, _ -> Bulma.p "You are disconnected."
|
2023-07-10 03:59:44 +02:00
|
|
|
true, Just rr_id -> modal_rr_delete rr_id
|
2023-07-09 14:26:47 +02:00
|
|
|
true, Nothing -> HH.div_ [ Bulma.h1 state._current_domain
|
|
|
|
, Bulma.hr
|
2023-07-09 05:14:29 +02:00
|
|
|
, render_records sorted
|
|
|
|
, render_mx_records state._mxrr
|
|
|
|
, render_srv_records state._srvrr
|
|
|
|
, render_new_records state
|
|
|
|
]
|
|
|
|
]
|
|
|
|
where
|
2023-07-10 20:33:28 +02:00
|
|
|
sorted = Foldable.foldl (<>) []
|
|
|
|
$ map (A.sortBy (comparing (_.domain)))
|
|
|
|
$ map NonEmpty.toArray
|
|
|
|
$ A.groupAllBy (comparing (_.t)) state._srr
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-10 03:59:44 +02:00
|
|
|
modal_rr_delete :: forall w. Int -> HH.HTML w Action
|
|
|
|
modal_rr_delete rr_id =
|
2023-07-09 05:14:29 +02:00
|
|
|
modal
|
|
|
|
[ modal_background
|
|
|
|
, modal_card [modal_header, modal_body]
|
|
|
|
, modal_foot [modal_delete_button, modal_cancel_button]
|
|
|
|
]
|
|
|
|
where
|
|
|
|
modal = HH.div [HP.classes (C.modal <> C.is_active)]
|
|
|
|
modal_background = HH.div [HP.classes C.modal_background] []
|
|
|
|
modal_card = HH.div [HP.classes C.modal_card]
|
|
|
|
modal_header = HH.header [HP.classes C.modal_card_head]
|
|
|
|
[ HH.p [HP.classes C.modal_card_title] [HH.text "Deleting a resource record"]
|
|
|
|
]
|
|
|
|
modal_body = HH.section [HP.classes C.modal_card_body] [ warning_message ]
|
|
|
|
modal_foot = HH.div [HP.classes C.modal_card_foot]
|
|
|
|
modal_delete_button
|
|
|
|
= HH.button [ HP.classes (C.button <> C.is_success)
|
2023-07-10 03:59:44 +02:00
|
|
|
, HE.onClick \_ -> RemoveRR rr_id
|
2023-07-09 05:14:29 +02:00
|
|
|
] [HH.text "Delete the resource record."]
|
|
|
|
modal_cancel_button
|
|
|
|
= HH.button [ HP.classes C.button
|
|
|
|
, HE.onClick \_ -> CancelModal
|
|
|
|
] [HH.text "Cancel"]
|
|
|
|
warning_message
|
|
|
|
= HH.p [] [ HH.text $ "You are about to delete a resource record, this actions is "
|
|
|
|
, HH.strong_ [ HH.text "irreversible" ]
|
|
|
|
, HH.text "."
|
|
|
|
]
|
|
|
|
|
|
|
|
handleAction :: forall m. MonadAff m => Action -> H.HalogenM State Action () Output m Unit
|
|
|
|
handleAction = case _ of
|
|
|
|
CancelModal -> do
|
|
|
|
H.modify_ _ { active_modal = Nothing }
|
|
|
|
|
2023-07-10 03:59:44 +02:00
|
|
|
DeleteRRModal rr_id -> do
|
|
|
|
H.modify_ _ { active_modal = Just rr_id }
|
|
|
|
|
2023-07-09 05:14:29 +02:00
|
|
|
Initialize -> do
|
2023-07-10 03:59:44 +02:00
|
|
|
{ _current_domain } <- H.get
|
|
|
|
H.raise $ Log $ SimpleLog $ "Asking the server for the zone" <> _current_domain
|
|
|
|
message <- H.liftEffect $ DNSManager.serialize $ DNSManager.MkGetZone { domain: _current_domain }
|
|
|
|
H.raise $ MessageToSend message
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
Finalize -> do
|
|
|
|
H.raise $ Log $ SimpleLog "Finalized!"
|
|
|
|
|
2023-07-09 17:37:49 +02:00
|
|
|
UpdateNewSRRForm rr_update -> case rr_update of
|
|
|
|
Update_SRR_Type val -> do
|
2023-07-10 20:33:28 +02:00
|
|
|
let new_type = fromMaybe "unknown" (baseRecords A.!! val)
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new entry type: " <> new_type)
|
|
|
|
state <- H.get
|
2023-07-10 20:33:28 +02:00
|
|
|
H.modify_ _ { _current_entry = changeType state._current_entry (baseRecords A.!! val) }
|
2023-07-09 17:37:49 +02:00
|
|
|
Update_SRR_Domain val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new entry domain: " <> val)
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry { domain = val } }
|
|
|
|
Update_SRR_TTL val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new entry ttl: " <> val)
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry { ttl = val, valid = isInteger val } }
|
|
|
|
Update_SRR_Value val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new entry value: " <> val)
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry { value = val } }
|
2023-07-09 16:00:36 +02:00
|
|
|
|
|
|
|
UpdateNewMXForm rr_update -> case rr_update of
|
2023-07-09 05:14:29 +02:00
|
|
|
-- TODO: FIXME: test all inputs
|
2023-07-09 17:37:49 +02:00
|
|
|
Update_MX_Domain val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new MX entry domain: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_mx = state._current_entry_mx { domain = val } }
|
2023-07-09 05:14:29 +02:00
|
|
|
-- TODO: FIXME: test all inputs
|
2023-07-09 17:37:49 +02:00
|
|
|
Update_MX_TTL val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new MX entry ttl: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_mx = state._current_entry_mx {ttl = val, valid = isInteger val} }
|
2023-07-09 05:14:29 +02:00
|
|
|
-- TODO: FIXME: test all inputs
|
2023-07-09 17:37:49 +02:00
|
|
|
Update_MX_Value val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new MX entry value: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_mx = state._current_entry_mx { value = val } }
|
|
|
|
Update_MX_Priority val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new MX entry priority: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_mx = state._current_entry_mx { priority = val } }
|
2023-07-09 16:00:36 +02:00
|
|
|
|
|
|
|
UpdateNewSRVForm rr_update -> case rr_update of
|
2023-07-09 17:37:49 +02:00
|
|
|
Update_SRV_Domain val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new SRV entry domain: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_srv = state._current_entry_srv { domain = val } }
|
|
|
|
Update_SRV_Value val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new SRV entry value: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_srv = state._current_entry_srv { value = val } }
|
2023-07-09 16:00:36 +02:00
|
|
|
-- TODO: FIXME: test all inputs
|
2023-07-09 17:37:49 +02:00
|
|
|
Update_SRV_TTL val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new SRV entry ttl: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_srv = state._current_entry_srv {ttl = val, valid = isInteger val}}
|
|
|
|
Update_SRV_Priority val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new SRV entry priority: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_srv = state._current_entry_srv { priority = val } }
|
|
|
|
Update_SRV_Weight val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new SRV entry weight: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_srv = state._current_entry_srv { weight = val } }
|
|
|
|
Update_SRV_Port val -> do
|
2023-07-09 16:00:36 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Update new SRV entry port: " <> val)
|
|
|
|
state <- H.get
|
2023-07-09 17:37:49 +02:00
|
|
|
H.modify_ _ { _current_entry_srv = state._current_entry_srv { port = val } }
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
|
|
|
|
-- This action only is possible if inputs are correct.
|
2023-07-09 17:37:49 +02:00
|
|
|
AddSRR -> do
|
2023-07-09 05:14:29 +02:00
|
|
|
state <- H.get
|
2023-07-11 04:18:43 +02:00
|
|
|
let newrr = fromLocalSimpleRRRepresentationToResourceRecord state._current_entry
|
|
|
|
H.raise $ Log $ SimpleLog ("Add new simple RR: " <> show state._current_entry)
|
|
|
|
message <- H.liftEffect
|
|
|
|
$ DNSManager.serialize
|
|
|
|
$ DNSManager.MkAddRR { domain: state._current_domain, rr: newrr }
|
|
|
|
H.raise $ MessageToSend message
|
2023-07-09 05:14:29 +02:00
|
|
|
AddMX -> do
|
|
|
|
state <- H.get
|
2023-07-11 03:26:42 +02:00
|
|
|
let newrr = fromLocalMXRRRepresentationToResourceRecord state._current_entry_mx
|
2023-07-09 05:14:29 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Add new MX: " <> show state._current_entry_mx)
|
2023-07-11 02:00:29 +02:00
|
|
|
message <- H.liftEffect
|
|
|
|
$ DNSManager.serialize
|
|
|
|
$ DNSManager.MkAddRR { domain: state._current_domain, rr: newrr }
|
|
|
|
H.raise $ MessageToSend message
|
2023-07-09 05:14:29 +02:00
|
|
|
AddSRV -> do
|
|
|
|
state <- H.get
|
2023-07-11 04:18:43 +02:00
|
|
|
let newrr = fromLocalSRVRRepresentationToResourceRecord state._current_entry_srv
|
2023-07-09 05:14:29 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("Add new SRV: " <> show state._current_entry_srv)
|
2023-07-11 04:18:43 +02:00
|
|
|
message <- H.liftEffect
|
|
|
|
$ DNSManager.serialize
|
|
|
|
$ DNSManager.MkAddRR { domain: state._current_domain, rr: newrr }
|
|
|
|
H.raise $ MessageToSend message
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-09 17:37:49 +02:00
|
|
|
UpdateLocalSRRForm rr_id rr_update -> case rr_update of
|
|
|
|
Update_SRR_Type val -> do
|
2023-07-10 20:33:28 +02:00
|
|
|
let new_type = fromMaybe "unknown" (baseRecords A.!! val)
|
2023-07-09 17:37:49 +02:00
|
|
|
H.raise $ Log $ SimpleLog ("TODO: Update local RR " <> show rr_id <> " type: " <> new_type)
|
|
|
|
-- state <- H.get
|
2023-07-10 20:33:28 +02:00
|
|
|
-- H.modify_ _ { _srr = changeType state._current_entry (baseRecords A.!! val) }
|
2023-07-09 17:37:49 +02:00
|
|
|
Update_SRR_Domain val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local RR " <> show rr_id <> " domain: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srr = (update_domain rr_id val state._srr) }
|
|
|
|
Update_SRR_TTL val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local RR " <> show rr_id <> " TTL: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srr = (update_ttl rr_id val state._srr) }
|
|
|
|
Update_SRR_Value val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local RR " <> show rr_id <> " value: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srr = (update_value rr_id val state._srr) }
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-09 17:37:49 +02:00
|
|
|
UpdateLocalMXForm rr_id rr_update -> case rr_update of
|
|
|
|
-- TODO: FIXME: test all inputs
|
|
|
|
Update_MX_Domain val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local MX RR " <> show rr_id <> " domain: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _mxrr = (update_domain rr_id val state._mxrr) }
|
|
|
|
-- TODO: FIXME: test all inputs
|
|
|
|
Update_MX_TTL val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local MX " <> show rr_id <> " entry ttl: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _mxrr = (update_ttl rr_id val state._mxrr) }
|
|
|
|
-- TODO: FIXME: test all inputs
|
|
|
|
Update_MX_Value val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local MX " <> show rr_id <> " entry value: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _mxrr = (update_value rr_id val state._mxrr) }
|
|
|
|
Update_MX_Priority val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local MX " <> show rr_id <> " entry priority: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _mxrr = (update_priority rr_id val state._mxrr) }
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-09 17:37:49 +02:00
|
|
|
UpdateLocalSRVForm rr_id rr_update -> case rr_update of
|
|
|
|
Update_SRV_Domain val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local SRV " <> show rr_id <> " entry domain: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srvrr = (update_domain rr_id val state._srvrr) }
|
|
|
|
Update_SRV_Value val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local SRV " <> show rr_id <> " entry value: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srvrr = (update_value rr_id val state._srvrr) }
|
|
|
|
-- TODO: FIXME: test all inputs
|
|
|
|
Update_SRV_TTL val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local SRV " <> show rr_id <> " entry ttl: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srvrr = (update_ttl rr_id val state._srvrr) }
|
|
|
|
Update_SRV_Priority val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local SRV " <> show rr_id <> " entry priority: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srvrr = (update_priority rr_id val state._srvrr) }
|
|
|
|
Update_SRV_Weight val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local SRV " <> show rr_id <> " entry weight: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srvrr = (update_weight rr_id val state._srvrr) }
|
|
|
|
Update_SRV_Port val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Update local SRV " <> show rr_id <> " entry port: " <> val)
|
|
|
|
state <- H.get
|
|
|
|
H.modify_ _ { _srvrr = (update_port rr_id val state._srvrr) }
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-09 17:37:49 +02:00
|
|
|
-- TODO: network operations
|
|
|
|
SyncRR rr_id -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("TODO: SyncRR: " <> show rr_id)
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-10 03:59:44 +02:00
|
|
|
RemoveRR rr_id -> do
|
|
|
|
{ _current_domain } <- H.get
|
|
|
|
H.raise $ Log $ SimpleLog $ "Ask to remove rr (id: " <> show rr_id <> ")"
|
|
|
|
message <- H.liftEffect
|
|
|
|
$ DNSManager.serialize
|
|
|
|
$ DNSManager.MkDeleteRR { domain: _current_domain, rrid: rr_id }
|
|
|
|
H.raise $ MessageToSend message
|
2023-07-11 02:00:29 +02:00
|
|
|
H.modify_ _ { active_modal = Nothing }
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
-- TODO: change the state to indicate problems?
|
2023-07-09 17:37:49 +02:00
|
|
|
TellSomethingWentWrong rr_id val -> do
|
|
|
|
H.raise $ Log $ SimpleLog ("Sorry, your record " <> show rr_id <> " has problems: ")
|
2023-07-09 05:14:29 +02:00
|
|
|
-- H.raise $ Log $ SimpleLog (show rr)
|
|
|
|
H.raise $ Log $ SimpleLog (" => " <> val)
|
|
|
|
|
|
|
|
handleQuery :: forall a m. MonadAff m => Query a -> H.HalogenM State Action () Output m (Maybe a)
|
|
|
|
handleQuery = case _ of
|
|
|
|
|
|
|
|
MessageReceived message a -> do
|
|
|
|
receivedMessage <- H.liftEffect $ DNSManager.deserialize message
|
|
|
|
case receivedMessage of
|
|
|
|
-- Cases where we didn't understand the message.
|
2023-07-10 05:01:08 +02:00
|
|
|
Left err -> do
|
|
|
|
--H.raise $ Log $ SimpleLog $ "[🤖] received a message that couldn't be decoded..., reason: " <> show err
|
|
|
|
case err of
|
|
|
|
(DNSManager.JSONERROR jerr) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[🤖] JSON parsing error: " <> jerr
|
|
|
|
(DNSManager.UnknownError unerr) ->
|
|
|
|
H.raise $ Log $ SimpleLog $ "[🤖] Parsing error: DNSManager.UnknownError" <> (show unerr)
|
|
|
|
(DNSManager.UnknownNumber ) ->
|
|
|
|
H.raise $ Log $ SimpleLog $ "[🤖] Parsing error: DNSManager.UnknownNumber"
|
2023-07-09 05:14:29 +02:00
|
|
|
pure Nothing
|
|
|
|
|
|
|
|
-- Cases where we understood the message.
|
|
|
|
Right received_msg -> do
|
|
|
|
case received_msg of
|
|
|
|
-- The authentication failed.
|
|
|
|
(DNSManager.MkError errmsg) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[😈] Failed, reason is: " <> errmsg.reason
|
|
|
|
(DNSManager.MkErrorUserNotLogged _) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[😈] Failed! The user isn't connected!"
|
|
|
|
H.raise $ Log $ SimpleLog $ "[🤖] Trying to authenticate to fix the problem..."
|
|
|
|
H.raise $ DNSManagerReconnect
|
|
|
|
(DNSManager.MkErrorInvalidToken _) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[TODO] Failed connection! Invalid token!"
|
|
|
|
(DNSManager.MkDomainAlreadyExists _) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[TODO] Failed! The domain already exists."
|
|
|
|
(DNSManager.MkUnacceptableDomain _) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[TODO] Failed! The domain is not acceptable (not in the list of accepted domains)."
|
|
|
|
|
2023-07-10 20:33:28 +02:00
|
|
|
(DNSManager.MkAcceptedDomains _) -> do
|
2023-07-09 05:14:29 +02:00
|
|
|
H.raise $ Log $ SimpleLog $ "[TODO] Received the list of accepted domains!"
|
|
|
|
|
2023-07-10 20:33:28 +02:00
|
|
|
(DNSManager.MkLogged _) -> do
|
2023-07-09 05:14:29 +02:00
|
|
|
H.raise $ Log $ SimpleLog $ "[TODO] Authenticated to dnsmanagerd!"
|
|
|
|
|
|
|
|
(DNSManager.MkDomainAdded response) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[TODO] Domain added: " <> response.domain
|
2023-07-11 03:26:42 +02:00
|
|
|
|
|
|
|
(DNSManager.MkRRAdded response) -> do
|
|
|
|
state <- H.get
|
|
|
|
let new_rr = response.rr
|
|
|
|
H.raise $ Log $ SimpleLog
|
|
|
|
$ "[TODO] Resource Record added: " <> response.domain
|
|
|
|
<> " rrid: " <> show new_rr.rrid
|
|
|
|
<> " rrtype: " <> new_rr.rrtype
|
|
|
|
<> " name: " <> new_rr.name
|
|
|
|
<> " ttl: " <> show new_rr.ttl
|
|
|
|
<> " target: " <> new_rr.target
|
|
|
|
<> " readonly: " <> show new_rr.readonly
|
|
|
|
case add_entry state new_rr of
|
|
|
|
Left error_message -> H.raise $ Log $ SimpleLog $ "Error while adding new entry: " <> error_message
|
|
|
|
Right new_state -> H.put new_state
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
(DNSManager.MkInvalidDomainName _) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[😈] Failed! The domain is not valid!"
|
|
|
|
|
|
|
|
(DNSManager.MkDomainDeleted response) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[TODO] The domain '" <> response.domain <> "' has been deleted!"
|
2023-07-10 03:59:44 +02:00
|
|
|
(DNSManager.MkRRDeleted response) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[🎉] RR (id: '" <> show response.rrid <> "') has been deleted!"
|
|
|
|
state <- H.get
|
2023-07-10 20:33:28 +02:00
|
|
|
H.modify_ _ { _srr = A.filter (\rr -> rr.id /= response.rrid) state._srr
|
|
|
|
, _mxrr = A.filter (\rr -> rr.id /= response.rrid) state._mxrr
|
|
|
|
, _srvrr = A.filter (\rr -> rr.id /= response.rrid) state._srvrr
|
2023-07-10 03:59:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
(DNSManager.MkZone response) -> do
|
2023-07-11 04:18:43 +02:00
|
|
|
H.raise $ Log $ SimpleLog $ "[🎉] Zone received!"
|
2023-07-11 03:43:16 +02:00
|
|
|
add_entries response.zone.resources
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-11 04:18:43 +02:00
|
|
|
(DNSManager.MkInvalidRR response) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[😈] Invalid resource record: " <> A.intercalate ", " response.errors
|
|
|
|
|
2023-07-09 05:14:29 +02:00
|
|
|
(DNSManager.MkSuccess _) -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "[🎉] Success!"
|
|
|
|
-- WTH?!
|
|
|
|
_ -> do
|
2023-07-11 04:18:43 +02:00
|
|
|
H.raise $ Log $ SimpleLog $ "[😈] Failed! dnsmanager daemon didn't send a valid message."
|
2023-07-09 05:14:29 +02:00
|
|
|
pure (Just a)
|
|
|
|
|
|
|
|
ConnectionIsDown a -> do
|
|
|
|
H.modify_ _ { wsUp = false }
|
|
|
|
pure (Just a)
|
|
|
|
|
|
|
|
ConnectionIsUp a -> do
|
|
|
|
H.modify_ _ { wsUp = true }
|
|
|
|
pure (Just a)
|
|
|
|
|
2023-07-10 05:01:08 +02:00
|
|
|
where
|
2023-07-11 03:43:16 +02:00
|
|
|
add_entries [] = H.raise $ Log $ SimpleLog "Done adding entries"
|
|
|
|
add_entries arr = do
|
|
|
|
state <- H.get
|
|
|
|
case A.head arr, A.tail arr of
|
|
|
|
Nothing, _ -> H.raise $ Log $ SimpleLog "Done adding entries (but why this didn't performed pattern matching??)"
|
|
|
|
Just new_rr, tail -> case add_entry state new_rr of
|
|
|
|
Left error_message -> do
|
|
|
|
H.raise $ Log $ SimpleLog $ "Error while adding new entry: " <> error_message
|
|
|
|
add_entries $ fromMaybe [] tail
|
|
|
|
Right new_state -> do
|
|
|
|
H.put new_state
|
|
|
|
add_entries $ fromMaybe [] tail
|
|
|
|
|
2023-07-11 03:26:42 +02:00
|
|
|
add_entry :: State -> ResourceRecord -> Either String State
|
|
|
|
add_entry state new_rr = do
|
|
|
|
case new_rr.rrtype, (A.elem new_rr.rrtype baseRecords) of
|
|
|
|
_, true -> Right $ add_new_entry state $ fromResourceRecordToLocalRepresentationSimpleRR new_rr
|
|
|
|
"MX", _ -> Right $ add_new_mx state $ fromResourceRecordToLocalRepresentationMXRR new_rr
|
|
|
|
"SRV", _ -> Right $ add_new_srv state $ fromResourceRecordToLocalRepresentationSRVRR new_rr
|
|
|
|
_, _ -> Left "TODO: CAN'T ADD THIS KIND OF RR RIGHT NOW"
|
|
|
|
|
2023-07-09 05:14:29 +02:00
|
|
|
-- Rendering
|
|
|
|
class_title_size :: Array (HH.ClassName)
|
|
|
|
class_title_size = [HH.ClassName "is-4"]
|
|
|
|
|
|
|
|
render_records :: forall (w :: Type). Array (SimpleRR ()) -> HH.HTML w Action
|
|
|
|
render_records []
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.columns [] [ left_block, right_block ]
|
|
|
|
where left_block = Bulma.column class_title_size
|
|
|
|
[ Bulma.zone_rr_title "NS, A, AAAA, CNAME"
|
|
|
|
, Bulma.subtitle "and TXT records"
|
|
|
|
]
|
|
|
|
right_block = Bulma.column_ [ Bulma.subtitle "No records for now" ]
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
render_records records
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.columns [] [ Bulma.column class_title_size [Bulma.zone_rr_title title_txt, Bulma.subtitle subtitle_txt ]
|
|
|
|
, Bulma.column_ [ Bulma.tile [ table_rr ] ]
|
|
|
|
]
|
2023-07-09 05:14:29 +02:00
|
|
|
where
|
|
|
|
title_txt = "NS, A, AAAA, CNAME"
|
|
|
|
subtitle_txt = "and TXT records"
|
|
|
|
-- subtitle_txt = "Each line is a resource record from your DNS zone."
|
|
|
|
-- <> " You can edit them, then click on the \"fix\" button to synchronize with the server."
|
2023-07-10 18:24:50 +02:00
|
|
|
table_rr = HH.table [] [ Bulma.simple_table_header, table_content ]
|
2023-07-09 05:14:29 +02:00
|
|
|
table_content = HH.tbody_ $ map row records
|
|
|
|
|
|
|
|
row rr = HH.tr_ $
|
2023-07-10 18:24:50 +02:00
|
|
|
[ Bulma.txt_name rr.t
|
2023-07-10 18:14:56 +02:00
|
|
|
, HH.td_ [ Bulma.input_domain ((UpdateLocalSRRForm rr.id) <<< Update_SRR_Domain) rr.domain rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_ttl ((UpdateLocalSRRForm rr.id) <<< Update_SRR_TTL ) rr.ttl rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_value ((UpdateLocalSRRForm rr.id) <<< Update_SRR_Value) rr.value rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.btn_change (SyncRR rr.id) (TellSomethingWentWrong rr.id "cannot update") rr.modified rr.valid ]
|
2023-07-11 02:00:29 +02:00
|
|
|
, HH.td_ [ Bulma.btn_delete (\_ -> DeleteRRModal rr.id) ]
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
render_mx_records :: forall (w :: Type) (l :: Row Type)
|
|
|
|
. Array (MXRR l) -> HH.HTML w Action
|
|
|
|
render_mx_records []
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.columns [] [ left_block, right_block ]
|
|
|
|
where left_block = Bulma.column class_title_size [ Bulma.zone_rr_title "MX records" ]
|
|
|
|
right_block = Bulma.column_ [ Bulma.subtitle "No records for now" ]
|
2023-07-09 05:14:29 +02:00
|
|
|
render_mx_records records
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.columns [] [ Bulma.column class_title_size [ Bulma.zone_rr_title title_txt ]
|
|
|
|
, Bulma.column_ [ Bulma.tile [ table_rr ] ]
|
|
|
|
]
|
2023-07-09 05:14:29 +02:00
|
|
|
where
|
|
|
|
title_txt = "MX records"
|
2023-07-10 18:24:50 +02:00
|
|
|
table_rr = HH.table [] [ Bulma.mx_table_header, table_content ]
|
2023-07-09 05:14:29 +02:00
|
|
|
table_content = HH.tbody_ $ map row records
|
|
|
|
|
|
|
|
row rr = HH.tr_ $
|
2023-07-10 18:14:56 +02:00
|
|
|
[ HH.td_ [ Bulma.input_domain ((UpdateLocalMXForm rr.id) <<< Update_MX_Domain) rr.domain rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_ttl ((UpdateLocalMXForm rr.id) <<< Update_MX_TTL) rr.ttl rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_priority ((UpdateLocalMXForm rr.id) <<< Update_MX_Priority) rr.priority rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_value ((UpdateLocalMXForm rr.id) <<< Update_MX_Value) rr.value rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.btn_change (SyncRR rr.id) (TellSomethingWentWrong rr.id "cannot update") rr.modified rr.valid ]
|
2023-07-11 02:00:29 +02:00
|
|
|
, HH.td_ [ Bulma.btn_delete (\_ -> DeleteRRModal rr.id) ]
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
render_srv_records :: forall (w :: Type) (l :: Row Type)
|
|
|
|
. Array (SRVRR l) -> HH.HTML w Action
|
|
|
|
render_srv_records []
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.columns [] [ left_block, right_block ]
|
|
|
|
where left_block = Bulma.column class_title_size [ Bulma.zone_rr_title "SRV records" ]
|
|
|
|
right_block = Bulma.column_ [ Bulma.subtitle "No records for now" ]
|
2023-07-09 05:14:29 +02:00
|
|
|
render_srv_records records
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.columns [] [ Bulma.column class_title_size [ Bulma.zone_rr_title title_txt]
|
|
|
|
, Bulma.column_ [ Bulma.tile [ table_rr ] ] ]
|
2023-07-09 05:14:29 +02:00
|
|
|
where
|
|
|
|
title_txt = "SRV records"
|
2023-07-10 18:24:50 +02:00
|
|
|
table_rr = HH.table [] [ Bulma.srv_table_header, table_content ]
|
2023-07-09 05:14:29 +02:00
|
|
|
table_content = HH.tbody_ $ map row records
|
|
|
|
|
|
|
|
row rr = HH.tr_ $
|
2023-07-10 18:14:56 +02:00
|
|
|
[ HH.td_ [ Bulma.input_domain ((UpdateLocalSRVForm rr.id) <<< Update_SRV_Domain ) rr.domain rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_ttl ((UpdateLocalSRVForm rr.id) <<< Update_SRV_TTL ) rr.ttl rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_priority ((UpdateLocalSRVForm rr.id) <<< Update_SRV_Priority) rr.priority rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_weight ((UpdateLocalSRVForm rr.id) <<< Update_SRV_Weight ) rr.weight rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_port ((UpdateLocalSRVForm rr.id) <<< Update_SRV_Port ) rr.port rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_value ((UpdateLocalSRVForm rr.id) <<< Update_SRV_Value ) rr.value rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.btn_change (SyncRR rr.id) (TellSomethingWentWrong rr.id "cannot update") rr.modified rr.valid ]
|
2023-07-11 02:00:29 +02:00
|
|
|
, HH.td_ [ Bulma.btn_delete (\_ -> DeleteRRModal rr.id) ]
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
baseRecords :: Array String
|
|
|
|
baseRecords = [ "NS", "A", "AAAA", "CNAME", "TXT" ]
|
|
|
|
|
|
|
|
render_new_record :: forall (w :: Type). (SimpleRR ()) -> HH.HTML w Action
|
|
|
|
render_new_record rr
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.hdiv [ Bulma.zone_rr_title "New record (NS, A, AAAA, CNAME, TXT)", table ]
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
where
|
2023-07-10 18:24:50 +02:00
|
|
|
table = HH.table [] [ Bulma.simple_table_header, render_record_builder ]
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
-- render_record_builder :: forall w. HH.HTML w Action
|
|
|
|
render_record_builder
|
|
|
|
= HH.tr_
|
|
|
|
[ HH.td_ [ type_selection ]
|
2023-07-10 18:14:56 +02:00
|
|
|
, HH.td_ [ Bulma.input_domain (UpdateNewSRRForm <<< Update_SRR_Domain) rr.domain rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_ttl (UpdateNewSRRForm <<< Update_SRR_TTL) rr.ttl rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_value (UpdateNewSRRForm <<< Update_SRR_Value) rr.value rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.btn_add AddSRR (TellSomethingWentWrong rr.id "cannot add") rr.valid ]
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
-- type_selection :: forall w i. HH.HTML w i
|
|
|
|
type_selection = HH.select
|
2023-07-09 17:37:49 +02:00
|
|
|
[ HE.onSelectedIndexChange (UpdateNewSRRForm <<< Update_SRR_Type) ]
|
2023-07-09 05:14:29 +02:00
|
|
|
$ map type_option baseRecords
|
|
|
|
type_option n
|
|
|
|
= HH.option
|
|
|
|
[ HP.value n
|
|
|
|
, HP.selected (n == rr.t)
|
|
|
|
] [ HH.text n ]
|
|
|
|
|
|
|
|
|
|
|
|
render_mx_new_record :: forall (w :: Type). (MXRR ()) -> HH.HTML w Action
|
|
|
|
render_mx_new_record rr
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.hdiv [ Bulma.zone_rr_title "New MX record", table ]
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
where
|
2023-07-10 18:24:50 +02:00
|
|
|
table = HH.table [] [ Bulma.mx_table_header, render_record_builder ]
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
-- render_record_builder :: forall w. HH.HTML w Action
|
|
|
|
render_record_builder
|
|
|
|
= HH.tr_
|
2023-07-10 18:14:56 +02:00
|
|
|
[ HH.td_ [ Bulma.input_domain (UpdateNewMXForm <<< Update_MX_Domain) rr.domain rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_ttl (UpdateNewMXForm <<< Update_MX_TTL) rr.ttl rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_priority (UpdateNewMXForm <<< Update_MX_Priority) rr.priority rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_value (UpdateNewMXForm <<< Update_MX_Value) rr.value rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.btn_add AddMX (TellSomethingWentWrong rr.id "cannot add") rr.valid ]
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
render_srv_new_record :: forall (w :: Type). (SRVRR ()) -> HH.HTML w Action
|
|
|
|
render_srv_new_record rr
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.hdiv [ Bulma.zone_rr_title "New SRV record", table ]
|
2023-07-09 05:14:29 +02:00
|
|
|
where
|
2023-07-10 18:24:50 +02:00
|
|
|
table = HH.table [] [ Bulma.srv_table_header, render_record_builder ]
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
-- render_record_builder :: forall w. HH.HTML w Action
|
|
|
|
render_record_builder
|
|
|
|
= HH.tr_
|
2023-07-10 18:14:56 +02:00
|
|
|
[ HH.td_ [ Bulma.input_domain (UpdateNewSRVForm <<< Update_SRV_Domain) rr.domain rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_ttl (UpdateNewSRVForm <<< Update_SRV_TTL) rr.ttl rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_priority (UpdateNewSRVForm <<< Update_SRV_Priority) rr.priority rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_weight (UpdateNewSRVForm <<< Update_SRV_Weight) rr.weight rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_port (UpdateNewSRVForm <<< Update_SRV_Port) rr.port rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.input_value (UpdateNewSRVForm <<< Update_SRV_Value) rr.value rr.valid ]
|
|
|
|
, HH.td_ [ Bulma.btn_add AddSRV (TellSomethingWentWrong rr.id "cannot add") rr.valid ]
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
-- Component definition and initial state
|
|
|
|
|
|
|
|
render_new_records :: forall (w :: Type). State -> HH.HTML w Action
|
|
|
|
render_new_records state
|
2023-07-10 18:14:56 +02:00
|
|
|
= Bulma.hdiv
|
2023-07-09 14:26:47 +02:00
|
|
|
[ Bulma.h1 "Adding new records"
|
|
|
|
, Bulma.hr
|
2023-07-10 18:14:56 +02:00
|
|
|
, Bulma.columns []
|
2023-07-09 05:14:29 +02:00
|
|
|
[ render_new_record_column_simple state._current_entry
|
|
|
|
, render_new_record_colunm_mx state._current_entry_mx
|
|
|
|
, render_new_record_colunm_srv state._current_entry_srv
|
|
|
|
-- , render_current_value state._current_entry
|
|
|
|
-- , render_mx_current_value state._current_entry_mx
|
|
|
|
-- , render_srv_current_value state._current_entry_srv
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
render_new_record_column_simple :: forall (w :: Type).
|
|
|
|
(SimpleRR ()) -> HH.HTML w Action
|
|
|
|
render_new_record_column_simple rr
|
2023-07-10 18:24:50 +02:00
|
|
|
= Bulma.column_ $ [ Bulma.box
|
2023-07-09 14:26:47 +02:00
|
|
|
[ Bulma.zone_rr_title "NS, A, AAAA, CNAME, TXT"
|
2023-07-09 05:14:29 +02:00
|
|
|
, type_selection
|
2023-07-10 18:14:56 +02:00
|
|
|
, Bulma.box_input_domain (UpdateNewSRRForm <<< Update_SRR_Domain) rr.domain rr.valid
|
|
|
|
, Bulma.box_input_ttl (UpdateNewSRRForm <<< Update_SRR_TTL) rr.ttl rr.valid
|
|
|
|
, Bulma.box_input_value (UpdateNewSRRForm <<< Update_SRR_Value) rr.value rr.valid
|
|
|
|
, Bulma.btn_add AddSRR (TellSomethingWentWrong rr.id "cannot add") rr.valid
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
]
|
|
|
|
where
|
|
|
|
-- type_selection :: forall w i. HH.HTML w i
|
|
|
|
type_selection = HH.select
|
2023-07-09 17:37:49 +02:00
|
|
|
[ HE.onSelectedIndexChange (UpdateNewSRRForm <<< Update_SRR_Type) ]
|
2023-07-09 05:14:29 +02:00
|
|
|
$ map type_option baseRecords
|
|
|
|
type_option n
|
|
|
|
= HH.option
|
|
|
|
[ HP.value n
|
|
|
|
, HP.selected (n == rr.t)
|
|
|
|
] [ HH.text n ]
|
|
|
|
|
|
|
|
|
|
|
|
render_new_record_colunm_mx :: forall (w :: Type). (MXRR ()) -> HH.HTML w Action
|
|
|
|
render_new_record_colunm_mx rr
|
2023-07-10 18:24:50 +02:00
|
|
|
= Bulma.column_ $ [ Bulma.box
|
2023-07-09 14:26:47 +02:00
|
|
|
[ Bulma.zone_rr_title "MX"
|
2023-07-10 18:14:56 +02:00
|
|
|
, Bulma.box_input_domain (UpdateNewMXForm <<< Update_MX_Domain) rr.domain rr.valid
|
|
|
|
, Bulma.box_input_ttl (UpdateNewMXForm <<< Update_MX_TTL) rr.ttl rr.valid
|
|
|
|
, Bulma.box_input_priority (UpdateNewMXForm <<< Update_MX_Priority) rr.priority rr.valid
|
|
|
|
, Bulma.box_input_value (UpdateNewMXForm <<< Update_MX_Value) rr.value rr.valid
|
|
|
|
, Bulma.btn_add AddMX (TellSomethingWentWrong rr.id "cannot add") rr.valid
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
render_new_record_colunm_srv :: forall (w :: Type). (SRVRR ()) -> HH.HTML w Action
|
|
|
|
render_new_record_colunm_srv rr
|
2023-07-10 18:24:50 +02:00
|
|
|
= Bulma.column_ $ [ Bulma.box
|
2023-07-09 14:26:47 +02:00
|
|
|
[ Bulma.zone_rr_title "SRV"
|
2023-07-10 18:14:56 +02:00
|
|
|
, Bulma.box_input_domain (UpdateNewSRVForm <<< Update_SRV_Domain) rr.domain rr.valid
|
|
|
|
, Bulma.box_input_ttl (UpdateNewSRVForm <<< Update_SRV_TTL) rr.ttl rr.valid
|
|
|
|
, Bulma.box_input_priority (UpdateNewSRVForm <<< Update_SRV_Priority) rr.priority rr.valid
|
|
|
|
, Bulma.box_input_weight (UpdateNewSRVForm <<< Update_SRV_Weight) rr.weight rr.valid
|
|
|
|
, Bulma.box_input_port (UpdateNewSRVForm <<< Update_SRV_Port) rr.port rr.valid
|
|
|
|
, Bulma.box_input_value (UpdateNewSRVForm <<< Update_SRV_Value) rr.value rr.valid
|
|
|
|
, Bulma.btn_add AddSRV (TellSomethingWentWrong rr.id "cannot add") rr.valid
|
2023-07-09 05:14:29 +02:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
-- ACTIONS
|
|
|
|
|
|
|
|
-- add a new record and get a new placeholter
|
2023-07-11 03:26:42 +02:00
|
|
|
add_new_entry :: State -> Maybe (SimpleRR ()) -> State
|
|
|
|
add_new_entry state = case _ of
|
|
|
|
Nothing -> state
|
|
|
|
Just rr -> state { _srr = (state._srr <> [ rr ]), _current_entry = defaultResourceA }
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
-- add a new record and get a new placeholter
|
2023-07-11 03:26:42 +02:00
|
|
|
add_new_mx :: State -> Maybe (MXRR ()) -> State
|
|
|
|
add_new_mx state = case _ of
|
|
|
|
Nothing -> state
|
|
|
|
Just rr -> state { _mxrr = (state._mxrr <> [ rr ]), _current_entry_mx = defaultResourceMX }
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
-- add a new record and get a new placeholter
|
2023-07-11 03:26:42 +02:00
|
|
|
add_new_srv :: State -> Maybe (SRVRR ()) -> State
|
|
|
|
add_new_srv state = case _ of
|
|
|
|
Nothing -> state
|
|
|
|
Just rr -> state { _srvrr = (state._srvrr <> [ rr ]), _current_entry_srv = defaultResourceSRV }
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
changeType :: forall (l :: Row Type). (SimpleRR l) -> Maybe String -> (SimpleRR l)
|
|
|
|
changeType rr Nothing = rr
|
|
|
|
changeType rr (Just s) = rr { t = s }
|
|
|
|
|
2023-07-09 17:37:49 +02:00
|
|
|
update_domain :: forall (l :: Row Type).
|
|
|
|
Int -> String -> Array (SimpleRR l) -> Array (SimpleRR l)
|
|
|
|
update_domain rr_id val
|
|
|
|
= update (\rr -> rr { modified = true, domain = val }) rr_id
|
|
|
|
|
2023-07-09 05:14:29 +02:00
|
|
|
update_value :: forall (l :: Row Type).
|
|
|
|
Int -> String -> Array (SimpleRR l) -> Array (SimpleRR l)
|
2023-07-09 17:37:49 +02:00
|
|
|
update_value rr_id val
|
|
|
|
= update (\rr -> rr { modified = true, value = val }) rr_id
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
update_ttl :: forall (l :: Row Type).
|
|
|
|
Int -> String -> Array (SimpleRR l) -> Array (SimpleRR l)
|
2023-07-09 17:37:49 +02:00
|
|
|
update_ttl rr_id val
|
|
|
|
= update (\rr -> rr { modified = true, ttl = val, valid = isInteger val }) rr_id
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
update_priority :: forall (l :: Row Type). Int -> Priority -> Array (MXRR l) -> Array (MXRR l)
|
2023-07-09 17:37:49 +02:00
|
|
|
update_priority rr_id val = update (\rr -> rr { modified = true, priority = val}) rr_id
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
update_weight :: forall (l :: Row Type). Int -> Priority -> Array (SRVRR l) -> Array (SRVRR l)
|
2023-07-09 17:37:49 +02:00
|
|
|
update_weight rr_id val = update (\rr -> rr { modified = true, weight = val}) rr_id
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
update_port :: Int -> Priority -> Array (SRVRR ()) -> Array (SRVRR ())
|
2023-07-09 17:37:49 +02:00
|
|
|
update_port rr_id val = update (\rr -> rr { modified = true, port = val}) rr_id
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-10 20:33:28 +02:00
|
|
|
isIntRegex :: Regex.Regex
|
|
|
|
isIntRegex = RegexUnsafe.unsafeRegex "^[0-9]*$" RegexFlags.noFlags
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
isInteger :: String -> Boolean
|
2023-07-10 20:33:28 +02:00
|
|
|
isInteger = Regex.test isIntRegex
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
update :: forall (l :: Row Type).
|
|
|
|
(SimpleRR l -> SimpleRR l) -> Int -> Array (SimpleRR l) -> Array (SimpleRR l)
|
2023-07-09 17:37:49 +02:00
|
|
|
update f rr_id records = map doSmth records
|
2023-07-09 05:14:29 +02:00
|
|
|
where
|
|
|
|
doSmth rr
|
2023-07-09 17:37:49 +02:00
|
|
|
| rr_id == rr.id = f rr
|
2023-07-09 05:14:29 +02:00
|
|
|
| otherwise = rr
|
|
|
|
|
2023-07-11 03:26:42 +02:00
|
|
|
fromResourceRecordToLocalRepresentationSimpleRR :: ResourceRecord -> Maybe (SimpleRR ())
|
|
|
|
fromResourceRecordToLocalRepresentationSimpleRR new_rr =
|
|
|
|
Just { t: new_rr.rrtype
|
|
|
|
, id: new_rr.rrid
|
|
|
|
, modified: false
|
|
|
|
, valid: true
|
|
|
|
, ttl: show new_rr.ttl
|
|
|
|
, domain: new_rr.name
|
|
|
|
, value: new_rr.target
|
|
|
|
}
|
|
|
|
|
|
|
|
fromResourceRecordToLocalRepresentationMXRR :: ResourceRecord -> Maybe (MXRR ())
|
|
|
|
fromResourceRecordToLocalRepresentationMXRR new_rr = do
|
|
|
|
priority <- new_rr.priority
|
|
|
|
Just { t: new_rr.rrtype
|
|
|
|
, id: new_rr.rrid
|
|
|
|
, modified: false
|
|
|
|
, valid: true
|
|
|
|
, ttl: show new_rr.ttl
|
|
|
|
, domain: new_rr.name
|
|
|
|
, value: new_rr.target
|
|
|
|
, priority: show priority
|
|
|
|
}
|
|
|
|
-- TODO: would be nice to have a simpler implementation, something like this:
|
|
|
|
--fromResourceRecordToLocalRepresentationMXRR new_rr
|
|
|
|
-- = let simple_rr = fromResourceRecordToLocalRepresentationSimpleRR new_rr
|
|
|
|
-- simple_rr { priority = show new_rr.priority }
|
|
|
|
|
|
|
|
fromResourceRecordToLocalRepresentationSRVRR :: ResourceRecord -> Maybe (SRVRR ())
|
|
|
|
fromResourceRecordToLocalRepresentationSRVRR new_rr = do
|
|
|
|
case new_rr.priority, new_rr.weight, new_rr.port of
|
|
|
|
Just priority, Just weight, Just port ->
|
|
|
|
Just { t: new_rr.rrtype
|
|
|
|
, id: new_rr.rrid
|
|
|
|
, modified: false
|
|
|
|
, valid: true
|
|
|
|
, ttl: show new_rr.ttl
|
|
|
|
, domain: new_rr.name
|
|
|
|
, value: new_rr.target
|
|
|
|
, priority: show priority
|
|
|
|
, port: show port
|
|
|
|
, weight: show weight
|
|
|
|
-- , protocol: protocol
|
|
|
|
}
|
|
|
|
_, _, _ -> Nothing
|
|
|
|
|
2023-07-11 04:18:43 +02:00
|
|
|
fromLocalSimpleRRRepresentationToResourceRecord :: SimpleRR () -> ResourceRecord
|
|
|
|
fromLocalSimpleRRRepresentationToResourceRecord form
|
|
|
|
= { rrtype: form.t
|
|
|
|
, rrid: form.id
|
|
|
|
, name: form.domain
|
|
|
|
, ttl: fromMaybe 3600 $ fromString form.ttl
|
|
|
|
, target: form.value
|
|
|
|
, readonly: false
|
|
|
|
, priority: Nothing
|
|
|
|
, port: Nothing
|
|
|
|
, protocol: Nothing
|
|
|
|
, weight: Nothing
|
|
|
|
, mname: Nothing
|
|
|
|
, rname: Nothing
|
|
|
|
, serial: Nothing
|
|
|
|
, refresh: Nothing
|
|
|
|
, retry: Nothing
|
|
|
|
, expire: Nothing
|
|
|
|
, minttl: Nothing
|
|
|
|
}
|
|
|
|
|
2023-07-11 03:26:42 +02:00
|
|
|
fromLocalMXRRRepresentationToResourceRecord :: MXRR () -> ResourceRecord
|
|
|
|
fromLocalMXRRRepresentationToResourceRecord form
|
|
|
|
= { rrtype: form.t
|
|
|
|
, rrid: form.id
|
|
|
|
, name: form.domain
|
|
|
|
, ttl: fromMaybe 3600 $ fromString form.ttl
|
|
|
|
, target: form.value
|
|
|
|
, readonly: false
|
|
|
|
, priority: Just $ fromMaybe 10 $ fromString form.priority
|
|
|
|
, port: Nothing
|
|
|
|
, protocol: Nothing
|
|
|
|
, weight: Nothing
|
|
|
|
, mname: Nothing
|
|
|
|
, rname: Nothing
|
|
|
|
, serial: Nothing
|
|
|
|
, refresh: Nothing
|
|
|
|
, retry: Nothing
|
|
|
|
, expire: Nothing
|
|
|
|
, minttl: Nothing
|
|
|
|
}
|
2023-07-09 05:14:29 +02:00
|
|
|
|
2023-07-11 04:18:43 +02:00
|
|
|
fromLocalSRVRRepresentationToResourceRecord :: SRVRR () -> ResourceRecord
|
|
|
|
fromLocalSRVRRepresentationToResourceRecord form
|
|
|
|
= { rrtype: form.t
|
|
|
|
, rrid: form.id
|
|
|
|
, name: form.domain
|
|
|
|
, ttl: fromMaybe 3600 $ fromString form.ttl
|
|
|
|
, target: form.value
|
|
|
|
, readonly: false
|
|
|
|
, priority: Just $ fromMaybe 10 $ fromString form.priority
|
|
|
|
, port: Just $ fromMaybe 10 $ fromString form.port
|
|
|
|
, protocol: Just "" -- TODO: 'protocol' seems to have been forgotten.
|
|
|
|
, weight: Just $ fromMaybe 10 $ fromString form.weight
|
|
|
|
, mname: Nothing
|
|
|
|
, rname: Nothing
|
|
|
|
, serial: Nothing
|
|
|
|
, refresh: Nothing
|
|
|
|
, retry: Nothing
|
|
|
|
, expire: Nothing
|
|
|
|
, minttl: Nothing
|
|
|
|
}
|
|
|
|
|
2023-07-09 05:14:29 +02:00
|
|
|
getNewID :: State -> Int
|
2023-07-10 20:33:28 +02:00
|
|
|
getNewID state = (_ + 1)
|
|
|
|
$ Foldable.foldl max 0 [ maxIDrr
|
|
|
|
, maxIDmxrr
|
|
|
|
, maxIDsrvrr
|
|
|
|
]
|
2023-07-09 05:14:29 +02:00
|
|
|
|
|
|
|
where
|
2023-07-10 20:33:28 +02:00
|
|
|
maxIDrr = Foldable.foldl max 0 $ map _.id state._srr
|
|
|
|
maxIDmxrr = Foldable.foldl max 0 $ map _.id state._mxrr
|
|
|
|
maxIDsrvrr = Foldable.foldl max 0 $ map _.id state._srvrr
|