onasty/web/src/Shared.elm(view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
module Shared exposing (Flags, Model, Msg, decoder, init, subscriptions, update)
import Api.Auth
import Auth.User
import Dict
import Effect exposing (Effect)
import Json.Decode
import JwtUtil
import Route exposing (Route)
import Route.Path
import Shared.Model
import Shared.Msg
import Task
import Time
-- FLAGS
type alias Flags =
{ accessToken : Maybe String
, refreshToken : Maybe String
, appUrl : String
}
decoder : Json.Decode.Decoder Flags
decoder =
Json.Decode.map3 Flags
(Json.Decode.field "access_token" (Json.Decode.maybe Json.Decode.string))
(Json.Decode.field "refresh_token" (Json.Decode.maybe Json.Decode.string))
(Json.Decode.field "app_url" Json.Decode.string)
-- INIT
type alias Model =
Shared.Model.Model
init : Result Json.Decode.Error Flags -> Route () -> ( Model, Effect Msg )
init flagsResult _ =
let
flags =
flagsResult |> Result.withDefault { accessToken = Nothing, refreshToken = Nothing, appUrl = "" }
maybeCredentials =
Maybe.map2 (\access refresh -> { accessToken = access, refreshToken = refresh })
flags.accessToken
flags.refreshToken
user =
case maybeCredentials of
Just credentials ->
Auth.User.SignedIn credentials
Nothing ->
Auth.User.NotSignedIn
in
( { user = user
, timeZone = Time.utc
, appURL = flags.appUrl
}
, Effect.batch
[ Time.now |> Task.perform Shared.Msg.CheckTokenExpiration |> Effect.sendCmd
, Time.here |> Task.perform Shared.Msg.GotZone |> Effect.sendCmd
]
)
-- UPDATE
type alias Msg =
Shared.Msg.Msg
update : Route () -> Msg -> Model -> ( Model, Effect Msg )
update _ msg model =
case msg of
Shared.Msg.GotZone timeZone ->
( { model | timeZone = timeZone }, Effect.none )
Shared.Msg.Logout ->
( { model | user = Auth.User.NotSignedIn }, Effect.clearUser )
Shared.Msg.SignedIn credentials ->
( { model | user = Auth.User.SignedIn credentials }
, Effect.batch
[ Effect.pushRoute
{ path = Route.Path.Home_
, query = Dict.empty
, hash = Nothing
}
, Effect.saveUser credentials.accessToken credentials.refreshToken
]
)
Shared.Msg.CheckTokenExpiration now ->
case model.user of
Auth.User.SignedIn credentials ->
if JwtUtil.isExpired now credentials.accessToken then
( model, Effect.refreshTokens )
else
( model, Effect.none )
_ ->
( model, Effect.none )
Shared.Msg.TriggerTokenRefresh ->
case model.user of
Auth.User.SignedIn credentials ->
( { model | user = Auth.User.RefreshingTokens }
, Api.Auth.refreshToken
{ onResponse = Shared.Msg.ApiRefreshTokensResponded
, refreshToken = credentials.refreshToken
}
)
_ ->
( model, Effect.none )
Shared.Msg.ApiRefreshTokensResponded (Ok credentials) ->
( { model | user = Auth.User.SignedIn credentials }
, Effect.saveUser credentials.accessToken credentials.refreshToken
)
Shared.Msg.ApiRefreshTokensResponded (Err _) ->
( { model | user = Auth.User.NotSignedIn }, Effect.clearUser )
-- SUBSCRIPTIONS
subscriptions : Route () -> Model -> Sub Msg
subscriptions _ _ =
Time.every (30 * 1000) Shared.Msg.CheckTokenExpiration
|