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