216 lines
4.8 KiB
Elm
216 lines
4.8 KiB
Elm
module Main exposing (..)
|
|
|
|
import Browser
|
|
import Browser.Navigation as Nav
|
|
import Html exposing (..)
|
|
import Html.Attributes exposing (..)
|
|
import Html.Events exposing (onInput)
|
|
import Http
|
|
import Json.Decode as D
|
|
import Url
|
|
|
|
-- MAIN
|
|
main : Program () Model Msg
|
|
main =
|
|
Browser.application
|
|
{ init = init
|
|
, view = view
|
|
, update = update
|
|
, subscriptions = subscriptions
|
|
, onUrlChange = UrlChanged
|
|
, onUrlRequest = LinkClicked
|
|
}
|
|
|
|
-- MODEL
|
|
type alias Model =
|
|
{ key : Nav.Key
|
|
, url : Url.Url
|
|
, token: Maybe String
|
|
, token_data: Maybe TokenData
|
|
, switch_data : Maybe ( List Switch )
|
|
}
|
|
|
|
init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
|
|
init flags url key =
|
|
( Model key url Nothing Nothing Nothing, Cmd.none )
|
|
|
|
-- UPDATE
|
|
type Msg
|
|
= LinkClicked Browser.UrlRequest
|
|
| UrlChanged Url.Url
|
|
| TokenInput String
|
|
| TokenValidate ( Result Http.Error TokenData )
|
|
| Logout
|
|
| NoSwitchData
|
|
| GotSwitchData ( List Switch )
|
|
|
|
type alias Switch
|
|
= { id : String
|
|
, who : String
|
|
, started_at : String
|
|
, ended_at : Maybe String
|
|
, duration : Int
|
|
}
|
|
|
|
type alias TokenData
|
|
= { sub : String
|
|
, jti : String
|
|
}
|
|
|
|
tokenDecoder : D.Decoder TokenData
|
|
tokenDecoder =
|
|
D.map2 TokenData
|
|
(D.field "sub" D.string)
|
|
(D.field "jti" D.string)
|
|
|
|
request method token path body expect =
|
|
Http.request
|
|
{ method = method
|
|
, body = body
|
|
, headers =
|
|
[ Http.header "Authorization" token
|
|
]
|
|
, url = path
|
|
, expect = expect
|
|
, timeout = Nothing
|
|
, tracker = Nothing
|
|
}
|
|
|
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
|
update msg model =
|
|
case msg of
|
|
LinkClicked urlRequest ->
|
|
case urlRequest of
|
|
Browser.Internal url ->
|
|
( model, Nav.pushUrl model.key (Url.toString url) )
|
|
|
|
Browser.External href ->
|
|
( model, Nav.load href )
|
|
|
|
UrlChanged url ->
|
|
case url.path of
|
|
"/logout" ->
|
|
( model, Nav.load "/" )
|
|
|
|
default ->
|
|
( { model | url = url }
|
|
, Cmd.none
|
|
)
|
|
|
|
TokenInput token ->
|
|
( { model | token = Just token }
|
|
, request "GET" token "/.within/tokeninfo" Http.emptyBody (expectJson TokenValidate tokenDecoder)
|
|
)
|
|
|
|
TokenValidate result ->
|
|
case result of
|
|
Ok data ->
|
|
( { model | token_data = Just data }
|
|
, Cmd.none
|
|
)
|
|
|
|
Err _ ->
|
|
( { model | token = Nothing }
|
|
, Cmd.none
|
|
)
|
|
|
|
Logout ->
|
|
( { model | token = Nothing, token_data = Nothing }
|
|
, Nav.load "/"
|
|
)
|
|
_ ->
|
|
( model, Cmd.none )
|
|
|
|
-- SUBSCRIPTIONS
|
|
subscriptions : Model -> Sub Msg
|
|
subscriptions _ =
|
|
Sub.none
|
|
|
|
-- VIEW
|
|
view : Model -> Browser.Document Msg
|
|
view model =
|
|
case model.token of
|
|
Nothing ->
|
|
template "Login"
|
|
[ h1 [] [ text "Login" ]
|
|
, viewInput "password" "API Token" "" TokenInput
|
|
]
|
|
Just token ->
|
|
case model.url.path of
|
|
"/" ->
|
|
template "Mi"
|
|
[ navBar
|
|
, h1 [] [ text "Mi" ]
|
|
, p [] [ text "TODO: everything" ]
|
|
, p []
|
|
[ text "Token sub: "
|
|
, text (Maybe.withDefault (TokenData "" "") model.token_data).sub
|
|
, text " ID: "
|
|
, text (Maybe.withDefault (TokenData "" "") model.token_data).jti
|
|
]
|
|
]
|
|
other ->
|
|
template "Not found"
|
|
[ navBar
|
|
, h1 [] [ text "Not found" ]
|
|
, p []
|
|
[ text "The requested URL "
|
|
, b [] [ text other ]
|
|
, text " was not found."
|
|
]
|
|
]
|
|
|
|
viewInput : String -> String -> String -> (String -> msg) -> Html msg
|
|
viewInput t p v toMsg =
|
|
input [ type_ t, placeholder p, value v, onInput toMsg ] []
|
|
|
|
viewLink : String -> String -> Html msg
|
|
viewLink path title =
|
|
a [ href path ] [ text title ]
|
|
|
|
template : String -> List (Html msg) -> Browser.Document msg
|
|
template title body =
|
|
{ title = title
|
|
, body =
|
|
[ node "main" []
|
|
body
|
|
]
|
|
}
|
|
|
|
navBar : Html msg
|
|
navBar =
|
|
node "nav" []
|
|
[ p []
|
|
[ viewLink "/" "Mi"
|
|
, text " - "
|
|
, viewLink "/switch" "Switch tracker"
|
|
, text " - "
|
|
, viewLink "/logout" "Logout"
|
|
]
|
|
]
|
|
|
|
expectJson : (Result Http.Error a -> msg) -> D.Decoder a -> Http.Expect msg
|
|
expectJson toMsg decoder =
|
|
Http.expectStringResponse toMsg <|
|
|
\response ->
|
|
case response of
|
|
Http.BadUrl_ url ->
|
|
Err (Http.BadUrl url)
|
|
|
|
Http.Timeout_ ->
|
|
Err Http.Timeout
|
|
|
|
Http.NetworkError_ ->
|
|
Err Http.NetworkError
|
|
|
|
Http.BadStatus_ metadata body ->
|
|
Err (Http.BadStatus metadata.statusCode)
|
|
|
|
Http.GoodStatus_ metadata body ->
|
|
case D.decodeString decoder body of
|
|
Ok value ->
|
|
Ok value
|
|
|
|
Err err ->
|
|
Err (Http.BadBody (D.errorToString err))
|