dnsmanager-webclient/src/App/Page/Migration.purs

194 lines
6 KiB
Text

-- | `App.Page.Migration` is the interface for migrated users before they validate their email address.
-- | To complete their migration, they need to provide an email address that will be validated with a token.
-- | This token will be required before the user can do anything else on the website.
-- |
-- | Exchanges between the webapp and authd:
-- |
-- | ```
-- | User gives a valid email address -> authd
-- | (authd accepts the email address and sends an email)
-- |
-- | authd -> email pending
-- | (we switch tab to "mail validation tab")
-- |
-- | User gives the received token -> authd
-- | (authd accepts the token and validates the email address)
-- |
-- | authd -> EmailChanged
-- | (webapp switches to domain list)
-- | ```
module App.Page.Migration where
import Prelude (Unit, between, bind, discard, map, pure, ($), (<>))
import Data.Array as A
import Data.ArrayBuffer.Types (ArrayBuffer)
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import Data.String as S
import Effect.Aff.Class (class MonadAff)
import Halogen as H
import Halogen.HTML as HH
import Halogen.HTML.Events as HE
import Web.Event.Event as Event
import Web.Event.Event (Event)
-- import Data.Generic.Rep (class Generic)
-- import Data.Show.Generic (genericShow)
import Bulma as Bulma
import Scroll (scrollToTop)
import App.Type.LogMessage
import App.Message.AuthenticationDaemon as AuthD
import App.DisplayErrors (show_error_email)
import App.Validation.Email as E
data Output = MessageToSend ArrayBuffer | Log LogMessage
-- | Once the new email address has been accepted by `authd` as "pending",
-- | this page automatically switches to a second tab.
data Query a = WaitingForToken a
type Slot = H.Slot Query Output
type Input = Unit
-- | Both value types to validate before sending the appropriate messages to `authd`.
data Subject = EmailAddress | Token
--derive instance eqSubject :: Eq Subject
--derive instance genericSubject :: Generic Subject _
--instance showSubject :: Show Subject where
-- show = genericShow
data Action
-- | Copy user input in the different HTML inputs.
= UserInput Subject String
-- | Verify either the format of the new email address or the token then send the request.
| Verify Subject Event
-- | Send either the new email address or the token to `authd`.
| ContactAuthd Subject
-- | Change the current tab.
-- | ChangeTab Subject
-- | The possible errors from the email format.
-- | TODO: check the token.
data Error = Email (Array E.Error)
-- | State is composed of the new email address, the token and the possible errors.
type State
= { email :: String
, token :: String
, errors :: Array Error
-- , current_tab :: Subject
}
initialState :: Input -> State
initialState _
= { email: ""
, token: ""
, errors: []
-- , current_tab: EmailAddress
}
component :: forall m. MonadAff m => H.Component Query Input Output m
component =
H.mkComponent
{ initialState
, render
, eval: H.mkEval $ H.defaultEval
{ handleAction = handleAction
, handleQuery = handleQuery
}
}
handleQuery :: forall a m. MonadAff m => Query a -> H.HalogenM State Action () Output m (Maybe a)
handleQuery = case _ of
-- TODO
WaitingForToken a -> pure (Just a)
render :: forall m. State -> H.ComponentHTML Action () m
render state
= Bulma.section_small [Bulma.columns_
[ b email_form
, b token_form
]]
where
b e = Bulma.column_ [ Bulma.box e ]
email_form
= [ Bulma.h3 "New Email address"
-- TODO: put some text here
, HH.form
[ HE.onSubmit (Verify EmailAddress) ]
[ email_input, email_error, Bulma.btn_validation ]
]
email_input = Bulma.email_input "Email" state.email (UserInput EmailAddress)
email_error
= case between 0 5 (S.length state.email), E.email state.email of
true, _ -> HH.text ""
_, Left errors -> Bulma.error_box "newAddress" "Email error" (show_error $ Email errors)
_, Right _ -> HH.text ""
token_form
= [ Bulma.h3 "Email validation token"
-- TODO: put some text here
, HH.form
[ HE.onSubmit (Verify Token) ]
[ token_input {-, token_error -}, Bulma.btn_validation ]
]
token_input = Bulma.token_input "Token" state.token (UserInput Token)
handleAction :: forall m. MonadAff m => Action -> H.HalogenM State Action () Output m Unit
handleAction = case _ of
UserInput subject value -> do
case subject of
EmailAddress -> H.modify_ _ { email = value }
Token -> H.modify_ _ { token = value }
-- Validate either the email address or the token then send the related requests to `authd`.
Verify subject ev -> do
H.liftEffect $ Event.preventDefault ev
state <- H.get
case subject of
EmailAddress -> do
case state.email of
"" -> do
H.raise $ Log $ UnableToSend "Please, write your new email address."
H.liftEffect scrollToTop
_ -> do
case E.email state.email of
Left errors -> H.raise $ Log $ UnableToSend $ show_error $ Email errors
Right _ -> handleAction $ ContactAuthd EmailAddress
Token -> do
case state.token of
"" -> do
H.raise $ Log $ UnableToSend "Please, write your validation token."
H.liftEffect scrollToTop
_ -> handleAction $ ContactAuthd Token
ContactAuthd subject -> do
state <- H.get
case subject of
EmailAddress -> do
message <- H.liftEffect $ AuthD.serialize $ AuthD.MkNewEmailAddress { email: state.email }
H.raise $ MessageToSend message
H.raise $ Log $ SystemLog $ "Sending a new email address."
Token -> do
message <- H.liftEffect $ AuthD.serialize $ AuthD.MkNewEmailAddressToken { token: state.token }
H.raise $ MessageToSend message
H.raise $ Log $ SystemLog $ "Sending a validation token."
show_error :: Error -> String
show_error = case _ of
Email arr -> "Error with the Email: " <> (A.fold $ map show_error_email arr)