diff --git a/src/api/App.fs b/src/api/App.fs index 2a16600..76a15ad 100644 --- a/src/api/App.fs +++ b/src/api/App.fs @@ -33,7 +33,7 @@ with } /// Application configuration -type Config = { +type AppConfig = { /// PostgreSQL connection string Conn : string /// Auth0 settings @@ -45,40 +45,45 @@ with Auth0 = Auth0Config.empty } - /// A JSON response as a data property type JsonOkResponse<'a> = { data : 'a } - /// A JSON response indicating an error occurred type JsonErrorResponse = { error : string } -// --- Support --- -/// Configuration instance -let cfg = - try - use sr = File.OpenText "appsettings.json" - use tr = new JsonTextReader (sr) - let settings = JToken.ReadFrom tr - let secret = settings.["auth0"].["client-secret"].ToObject() - { Conn = settings.["conn"].ToObject() - Auth0 = - { Domain = settings.["auth0"].["domain"].ToObject() - ClientId = settings.["auth0"].["client-id"].ToObject() - ClientSecret = secret - ClientSecretJwt = secret.TrimEnd('=').Replace("-", "+").Replace("_", "/") - } +/// Configuration instances +module Config = + + /// Application configuration + let app = + try + use sr = File.OpenText "appsettings.json" + use tr = new JsonTextReader (sr) + let settings = JToken.ReadFrom tr + let secret = settings.["auth0"].["client-secret"].ToObject() + { Conn = settings.["conn"].ToObject() + Auth0 = + { Domain = settings.["auth0"].["domain"].ToObject() + ClientId = settings.["auth0"].["client-id"].ToObject() + ClientSecret = secret + ClientSecretJwt = secret.TrimEnd('=').Replace("-", "+").Replace("_", "/") + } + } + with _ -> AppConfig.empty + + /// Custom Suave configuration + let suave = + { defaultConfig with + homeFolder = Some (Path.GetFullPath "./wwwroot/") + serverKey = Text.Encoding.UTF8.GetBytes("12345678901234567890123456789012") + bindings = [ HttpBinding.createSimple HTTP "127.0.0.1" 8084 ] } - with _ -> Config.empty -/// Get the scheme, host, and port of the URL -let schemeHostPort (req : HttpRequest) = - sprintf "%s://%s" req.url.Scheme (req.headers |> List.filter (fun x -> fst x = "host") |> List.head |> snd) /// Authorization functions module Auth = @@ -93,7 +98,7 @@ module Auth = /// Get the user Id (sub) from a JSON Web Token let getIdFromToken jwt = try - let payload = Jose.JWT.Decode(jwt, cfg.Auth0.ClientSecretJwt) + let payload = Jose.JWT.Decode(jwt, Config.app.Auth0.ClientSecretJwt) let tokenExpires = jsDate (payload.["exp"].ToObject()) match tokenExpires > DateTime.UtcNow with | true -> Some (payload.["sub"].ToObject()) @@ -108,10 +113,16 @@ module Auth = let loggedOn = warbler (fun ctx -> match ctx.request.header "Authorization" with - | Choice1Of2 bearer -> Writers.setUserData "user" ((bearer.Split(' ').[1]) |> getIdFromToken) + | Choice1Of2 bearer -> Writers.setUserData "user" (getIdFromToken <| bearer.Split(' ').[1]) | _ -> Writers.setUserData "user" None) +// --- Support --- + +/// Get the scheme, host, and port of the URL +let schemeHostPort (req : HttpRequest) = + sprintf "%s://%s" req.url.Scheme (req.headers |> List.filter (fun x -> fst x = "host") |> List.head |> snd) + /// Serialize an object to JSON let toJson = JsonConvert.SerializeObject @@ -121,7 +132,7 @@ let read ctx key : 'value = /// Create a new data context let dataCtx () = - new DataContext (((DbContextOptionsBuilder()).UseNpgsql cfg.Conn).Options) + new DataContext (((DbContextOptionsBuilder()).UseNpgsql Config.app.Conn).Options) /// Ensure the EF context is created in the right format let ensureDatabase () = @@ -131,14 +142,6 @@ let ensureDatabase () = } |> Async.RunSynchronously -let suaveCfg = - { defaultConfig with - homeFolder = Some (Path.GetFullPath "./wwwroot/") - serverKey = Text.Encoding.UTF8.GetBytes("12345678901234567890123456789012") - bindings = [ HttpBinding.createSimple HTTP "127.0.0.1" 8084 ] - } - -// --- Routes --- /// URL routes for myPrayerJournal module Route = @@ -147,8 +150,6 @@ module Route = let journal = "/api/journal" -// --- WebParts --- - /// All WebParts that compose the public API module WebParts = @@ -163,7 +164,6 @@ module WebParts = /// WebPart to return an JSON error response let errorJSON code error = jsonMimeType - >=> Writers.setStatus code >=> Response.response code ((toJson >> UTF8.bytes) { error = error }) /// Journal page @@ -177,12 +177,12 @@ module WebParts = let app = Auth.loggedOn >=> choose [ - path Route.journal >=> viewJournal + GET >=> path Route.journal >=> viewJournal errorJSON HttpCode.HTTP_404 "Page not found" ] [] let main argv = ensureDatabase () - startWebServer suaveCfg WebParts.app + startWebServer Config.suave WebParts.app 0 diff --git a/src/app/index.html b/src/app/index.html index d19689c..6082ad6 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -5,7 +5,6 @@ myPrayerJournal -
diff --git a/src/app/src/App.vue b/src/app/src/App.vue index cc9d719..ef6baa4 100644 --- a/src/app/src/App.vue +++ b/src/app/src/App.vue @@ -19,8 +19,14 @@ export default {