frontend: start to do switch data

This commit is contained in:
Cadey Ratio 2020-01-12 23:31:49 +00:00
parent a364713031
commit da98792d35
4 changed files with 258 additions and 156 deletions

View File

@ -5,7 +5,6 @@ import (
"encoding/hex"
"flag"
"net/http"
"strings"
"time"
"github.com/google/uuid"
@ -69,8 +68,10 @@ var publicRoutes map[string]bool
func init() {
publicRoutes = map[string]bool{
"/webhooks/": true,
"/static/": true,
"/webhooks/": true,
"/static/": true,
"/static/main.js": true,
"/static/gruvbox.css": true,
}
}
@ -91,7 +92,7 @@ func (pm PasetoMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
for k := range publicRoutes {
if strings.HasPrefix(r.URL.EscapedPath(), k) {
if r.URL.EscapedPath() == k {
goto ok
}
}

View File

@ -11,12 +11,14 @@
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/url": "1.0.0"
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"rtfeldman/elm-iso8601-date-strings": "1.1.3"
},
"indirect": {
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/time": "1.0.0",
"elm/parser": "1.1.0",
"elm/virtual-dom": "1.0.2"
}
},

View File

@ -7,209 +7,278 @@ import Html.Attributes exposing (..)
import Html.Events exposing (onInput)
import Http
import Json.Decode as D
import SwitchData
import Url
import Url.Builder
-- MAIN
main : Program () Model Msg
main =
Browser.application
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
, onUrlChange = UrlChanged
, onUrlRequest = LinkClicked
Browser.application
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
, onUrlChange = UrlChanged
, onUrlRequest = LinkClicked
}
type alias Model =
{ key : Nav.Key
, url : Url.Url
, token : Maybe String
, token_data : Maybe TokenData
, switch_cursor : ( Int, Int )
, switch_data : Maybe (List SwitchData.Switch)
}
-- 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 )
( Model
key
url
Nothing
Nothing
( 40, 0 )
Nothing
, Cmd.none
)
-- UPDATE
type Msg
= LinkClicked Browser.UrlRequest
| UrlChanged Url.Url
| TokenInput String
| TokenValidate ( Result Http.Error TokenData )
| Logout
| NoSwitchData
| GotSwitchData ( List Switch )
= LinkClicked Browser.UrlRequest
| UrlChanged Url.Url
| TokenInput String
| TokenValidate (Result Http.Error TokenData)
| Logout
| GetSwitchData ( Int, Int )
| GotSwitchData (Result Http.Error (List SwitchData.Switch))
type alias Switch
= { id : String
, who : String
, started_at : String
, ended_at : Maybe String
, duration : Int
}
type alias TokenData
= { sub : String
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)
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
}
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) )
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 )
Browser.External href ->
( model, Nav.load href )
UrlChanged url ->
case url.path of
"/logout" ->
( model, Nav.load "/" )
UrlChanged url ->
case url.path of
"/logout" ->
( model, Nav.load "/" )
default ->
( { model | url = url }
, Cmd.none
)
default ->
( { model | url = url }
, Cmd.none
)
TokenInput token ->
( { model | token = Just token }
, request "GET" token "/.within/tokeninfo" Http.emptyBody (expectJson TokenValidate tokenDecoder)
)
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
)
TokenValidate result ->
case result of
Ok data ->
( { model | token_data = Just data }
, Cmd.none
)
Err _ ->
( { model | token = Nothing }
, Cmd.none
)
Err _ ->
( { model | token = Nothing }
, Cmd.none
)
Logout ->
( { model | token = Nothing, token_data = Nothing }
, Nav.load "/"
)
GetSwitchData ( limit, page ) ->
case model.token of
Just token ->
( model
, request "GET"
token
(SwitchData.dataURL limit page)
Http.emptyBody
(expectJson GotSwitchData (D.list SwitchData.decoder))
)
Nothing ->
( model, Cmd.none )
_ ->
( model, Cmd.none )
Logout ->
( { model | token = Nothing, token_data = Nothing }
, Nav.load "/"
)
_ ->
( model, Cmd.none )
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
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."
]
]
case model.token_data of
Nothing ->
{ title = "Login"
, body =
[ node "main"
[ style "align" "center" ]
[ h1 [] [ text "Login" ]
, viewInput "password" "API Token" "" TokenInput
]
]
}
Just token_data ->
case model.url.path of
"/" ->
template "Mi"
[ h1 [] [ text "Mi" ]
, h2 [] [ text "TODO" ]
, ul []
[ li [] [ text "Switch CRUD" ]
, li [] [ text "POSSE manual announcement" ]
]
, h2 [] [ text "Token data" ]
, p []
[ text "Token sub: "
, text token_data.sub
, Html.br [] []
, text "ID: "
, text token_data.jti
]
]
"/switch" ->
case model.switch_data of
Nothing ->
template "Switch counter"
[ h1 [] [ text "Switch counter" ]
, p [] [ text "loading..." ]
]
Just switches ->
template "Switch counter"
[ h1 [] [ text "TODO: table" ]
]
other ->
template "Not found"
[ 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 ] []
input [ type_ t, placeholder p, value v, onInput toMsg ] []
viewLink : String -> String -> Html msg
viewLink path title =
a [ href path ] [ text title ]
a [ href path ] [ text title ]
template : String -> List (Html msg) -> Browser.Document msg
template title body =
{ title = title
, body =
[ node "main" []
body
]
}
{ title = title
, body =
[ node "main"
[]
[ navBar
, div [] body
, footer
]
]
}
navBar : Html msg
navBar =
node "nav" []
[ p []
[ viewLink "/" "Mi"
, text " - "
, viewLink "/switch" "Switch tracker"
, text " - "
, viewLink "/logout" "Logout"
]
]
node "nav"
[]
[ p []
[ viewLink "/" "Mi"
, text " - "
, viewLink "/switch" "Switch tracker"
, text " - "
, viewLink "/logout" "Logout"
]
]
footer : Html msg
footer =
node "footer"
[]
[ p []
[ a [ href "https://within.website" ] [ text "From Within" ]
, text " - "
, a [ href "https://tulpa.dev/cadey/mi" ] [ text "Source code" ]
]
]
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.expectStringResponse toMsg <|
\response ->
case response of
Http.BadUrl_ url ->
Err (Http.BadUrl url)
Http.Timeout_ ->
Err Http.Timeout
Http.Timeout_ ->
Err Http.Timeout
Http.NetworkError_ ->
Err Http.NetworkError
Http.NetworkError_ ->
Err Http.NetworkError
Http.BadStatus_ metadata body ->
Err (Http.BadStatus metadata.statusCode)
Http.BadStatus_ metadata body ->
Err (Http.BadStatus metadata.statusCode)
Http.GoodStatus_ metadata body ->
case D.decodeString decoder body of
Ok value ->
Ok value
Http.GoodStatus_ metadata body ->
case D.decodeString decoder body of
Ok value ->
Ok value
Err err ->
Err (Http.BadBody (D.errorToString err))
Err err ->
Err (Http.BadBody (D.errorToString err))

View File

@ -0,0 +1,30 @@
module SwitchData exposing (..)
import Iso8601
import Json.Decode exposing (Decoder, field, int, map5, nullable, string)
import Time exposing (Posix)
import Url.Builder as UB
type alias Switch =
{ id : String
, who : String
, started_at : Posix
, ended_at : Maybe Posix
, duration : Int
}
decoder : Decoder Switch
decoder =
map5 Switch
(field "id" string)
(field "who" string)
(field "started_at" Iso8601.decoder)
(field "ended_at" (nullable Iso8601.decoder))
(field "duration" int)
dataURL : Int -> Int -> String
dataURL limit page =
UB.absolute [ "switches" ] [ UB.int "limit" limit, UB.int "page" page ]