Version 3.1 (#71)
- Fix request sorting - Send time zone, so request actions are displayed in local time - Make recurrence a true DU - Tweak the data store representation of a few other fields
This commit was merged in pull request #71.
This commit is contained in:
@@ -7,175 +7,163 @@ open System.IO
|
||||
/// Configuration functions for the application
|
||||
module Configure =
|
||||
|
||||
/// Configure the content root
|
||||
let contentRoot root =
|
||||
WebApplicationOptions (ContentRootPath = root) |> WebApplication.CreateBuilder
|
||||
/// Configure the content root
|
||||
let contentRoot root =
|
||||
WebApplicationOptions (ContentRootPath = root) |> WebApplication.CreateBuilder
|
||||
|
||||
|
||||
open Microsoft.Extensions.Configuration
|
||||
open Microsoft.Extensions.Configuration
|
||||
|
||||
/// Configure the application configuration
|
||||
let appConfiguration (bldr : WebApplicationBuilder) =
|
||||
bldr.Configuration
|
||||
.SetBasePath(bldr.Environment.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", optional = false, reloadOnChange = true)
|
||||
.AddJsonFile($"appsettings.{bldr.Environment.EnvironmentName}.json", optional = true, reloadOnChange = true)
|
||||
.AddEnvironmentVariables ()
|
||||
|> ignore
|
||||
bldr
|
||||
/// Configure the application configuration
|
||||
let appConfiguration (bldr : WebApplicationBuilder) =
|
||||
bldr.Configuration
|
||||
.SetBasePath(bldr.Environment.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", optional = false, reloadOnChange = true)
|
||||
.AddJsonFile($"appsettings.{bldr.Environment.EnvironmentName}.json", optional = true, reloadOnChange = true)
|
||||
.AddEnvironmentVariables ()
|
||||
|> ignore
|
||||
bldr
|
||||
|
||||
|
||||
open Microsoft.AspNetCore.Server.Kestrel.Core
|
||||
open Microsoft.AspNetCore.Server.Kestrel.Core
|
||||
|
||||
/// Configure Kestrel from appsettings.json
|
||||
let kestrel (bldr : WebApplicationBuilder) =
|
||||
let kestrelOpts (ctx : WebHostBuilderContext) (opts : KestrelServerOptions) =
|
||||
(ctx.Configuration.GetSection >> opts.Configure >> ignore) "Kestrel"
|
||||
bldr.WebHost.UseKestrel().ConfigureKestrel kestrelOpts |> ignore
|
||||
bldr
|
||||
/// Configure Kestrel from appsettings.json
|
||||
let kestrel (bldr : WebApplicationBuilder) =
|
||||
let kestrelOpts (ctx : WebHostBuilderContext) (opts : KestrelServerOptions) =
|
||||
(ctx.Configuration.GetSection >> opts.Configure >> ignore) "Kestrel"
|
||||
bldr.WebHost.UseKestrel().ConfigureKestrel kestrelOpts |> ignore
|
||||
bldr
|
||||
|
||||
|
||||
/// Configure the web root directory
|
||||
let webRoot pathSegments (bldr : WebApplicationBuilder) =
|
||||
Array.concat [ [| bldr.Environment.ContentRootPath |]; pathSegments ]
|
||||
|> (Path.Combine >> bldr.WebHost.UseWebRoot >> ignore)
|
||||
bldr
|
||||
/// Configure the web root directory
|
||||
let webRoot pathSegments (bldr : WebApplicationBuilder) =
|
||||
Array.concat [ [| bldr.Environment.ContentRootPath |]; pathSegments ]
|
||||
|> (Path.Combine >> bldr.WebHost.UseWebRoot >> ignore)
|
||||
bldr
|
||||
|
||||
|
||||
open Microsoft.Extensions.Logging
|
||||
open Microsoft.Extensions.Hosting
|
||||
open Microsoft.Extensions.Logging
|
||||
open Microsoft.Extensions.Hosting
|
||||
|
||||
/// Configure logging
|
||||
let logging (bldr : WebApplicationBuilder) =
|
||||
match bldr.Environment.IsDevelopment () with
|
||||
| true -> ()
|
||||
| false -> bldr.Logging.AddFilter (fun l -> l > LogLevel.Information) |> ignore
|
||||
bldr.Logging.AddConsole().AddDebug() |> ignore
|
||||
bldr
|
||||
/// Configure logging
|
||||
let logging (bldr : WebApplicationBuilder) =
|
||||
if bldr.Environment.IsDevelopment () then bldr.Logging.AddFilter (fun l -> l > LogLevel.Information) |> ignore
|
||||
bldr.Logging.AddConsole().AddDebug() |> ignore
|
||||
bldr
|
||||
|
||||
|
||||
open Giraffe
|
||||
open LiteDB
|
||||
open Microsoft.AspNetCore.Authentication.Cookies
|
||||
open Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||
open Microsoft.AspNetCore.Http
|
||||
open Microsoft.Extensions.DependencyInjection
|
||||
open Microsoft.IdentityModel.Protocols.OpenIdConnect
|
||||
open NodaTime
|
||||
open System
|
||||
open System.Text.Json
|
||||
open System.Text.Json.Serialization
|
||||
open System.Threading.Tasks
|
||||
open Giraffe
|
||||
open LiteDB
|
||||
open Microsoft.AspNetCore.Authentication.Cookies
|
||||
open Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||
open Microsoft.AspNetCore.Http
|
||||
open Microsoft.Extensions.DependencyInjection
|
||||
open Microsoft.IdentityModel.Protocols.OpenIdConnect
|
||||
open NodaTime
|
||||
open System
|
||||
open System.Text.Json
|
||||
open System.Text.Json.Serialization
|
||||
open System.Threading.Tasks
|
||||
|
||||
/// Configure dependency injection
|
||||
let services (bldr : WebApplicationBuilder) =
|
||||
let sameSite (opts : CookieOptions) =
|
||||
match opts.SameSite, opts.Secure with
|
||||
| SameSiteMode.None, false -> opts.SameSite <- SameSiteMode.Unspecified
|
||||
| _, _ -> ()
|
||||
/// Configure dependency injection
|
||||
let services (bldr : WebApplicationBuilder) =
|
||||
let sameSite (opts : CookieOptions) =
|
||||
match opts.SameSite, opts.Secure with
|
||||
| SameSiteMode.None, false -> opts.SameSite <- SameSiteMode.Unspecified
|
||||
| _, _ -> ()
|
||||
|
||||
bldr.Services
|
||||
.AddRouting()
|
||||
.AddGiraffe()
|
||||
.AddSingleton<IClock>(SystemClock.Instance)
|
||||
.Configure<CookiePolicyOptions>(
|
||||
fun (opts : CookiePolicyOptions) ->
|
||||
opts.MinimumSameSitePolicy <- SameSiteMode.Unspecified
|
||||
opts.OnAppendCookie <- fun ctx -> sameSite ctx.CookieOptions
|
||||
opts.OnDeleteCookie <- fun ctx -> sameSite ctx.CookieOptions)
|
||||
.AddAuthentication(
|
||||
/// Use HTTP "Bearer" authentication with JWTs
|
||||
fun opts ->
|
||||
opts.DefaultAuthenticateScheme <- CookieAuthenticationDefaults.AuthenticationScheme
|
||||
opts.DefaultSignInScheme <- CookieAuthenticationDefaults.AuthenticationScheme
|
||||
opts.DefaultChallengeScheme <- CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie()
|
||||
.AddOpenIdConnect("Auth0",
|
||||
/// Configure OIDC with Auth0 options from configuration
|
||||
fun opts ->
|
||||
let cfg = bldr.Configuration.GetSection "Auth0"
|
||||
opts.Authority <- sprintf "https://%s/" cfg["Domain"]
|
||||
opts.ClientId <- cfg["Id"]
|
||||
opts.ClientSecret <- cfg["Secret"]
|
||||
opts.ResponseType <- OpenIdConnectResponseType.Code
|
||||
|
||||
opts.Scope.Clear ()
|
||||
opts.Scope.Add "openid"
|
||||
opts.Scope.Add "profile"
|
||||
|
||||
opts.CallbackPath <- PathString "/user/log-on/success"
|
||||
opts.ClaimsIssuer <- "Auth0"
|
||||
opts.SaveTokens <- true
|
||||
|
||||
opts.Events <- OpenIdConnectEvents ()
|
||||
opts.Events.OnRedirectToIdentityProviderForSignOut <- fun ctx ->
|
||||
let returnTo =
|
||||
match ctx.Properties.RedirectUri with
|
||||
| it when isNull it || it = "" -> ""
|
||||
| redirUri ->
|
||||
let finalRedirUri =
|
||||
match redirUri.StartsWith "/" with
|
||||
| true ->
|
||||
// transform to absolute
|
||||
let request = ctx.Request
|
||||
sprintf "%s://%s%s%s" request.Scheme request.Host.Value request.PathBase.Value redirUri
|
||||
| false -> redirUri
|
||||
Uri.EscapeDataString finalRedirUri |> sprintf "&returnTo=%s"
|
||||
sprintf "https://%s/v2/logout?client_id=%s%s" cfg["Domain"] cfg["Id"] returnTo
|
||||
|> ctx.Response.Redirect
|
||||
ctx.HandleResponse ()
|
||||
|
||||
Task.CompletedTask
|
||||
opts.Events.OnRedirectToIdentityProvider <- fun ctx ->
|
||||
let bldr = UriBuilder ctx.ProtocolMessage.RedirectUri
|
||||
bldr.Scheme <- cfg["Scheme"]
|
||||
bldr.Port <- int cfg["Port"]
|
||||
ctx.ProtocolMessage.RedirectUri <- string bldr
|
||||
Task.CompletedTask
|
||||
)
|
||||
|> ignore
|
||||
let jsonOptions = JsonSerializerOptions ()
|
||||
jsonOptions.Converters.Add (JsonFSharpConverter ())
|
||||
let db = new LiteDatabase (bldr.Configuration.GetConnectionString "db")
|
||||
Data.Startup.ensureDb db
|
||||
bldr.Services.AddSingleton(jsonOptions)
|
||||
.AddSingleton<Json.ISerializer, SystemTextJson.Serializer>()
|
||||
.AddSingleton<LiteDatabase> db
|
||||
|> ignore
|
||||
bldr.Build ()
|
||||
let _ = bldr.Services.AddRouting ()
|
||||
let _ = bldr.Services.AddGiraffe ()
|
||||
let _ = bldr.Services.AddSingleton<IClock> SystemClock.Instance
|
||||
let _ = bldr.Services.AddSingleton<IDateTimeZoneProvider> DateTimeZoneProviders.Tzdb
|
||||
|
||||
let _ =
|
||||
bldr.Services.Configure<CookiePolicyOptions>(fun (opts : CookiePolicyOptions) ->
|
||||
opts.MinimumSameSitePolicy <- SameSiteMode.Unspecified
|
||||
opts.OnAppendCookie <- fun ctx -> sameSite ctx.CookieOptions
|
||||
opts.OnDeleteCookie <- fun ctx -> sameSite ctx.CookieOptions)
|
||||
let _ =
|
||||
bldr.Services.AddAuthentication(fun opts ->
|
||||
opts.DefaultAuthenticateScheme <- CookieAuthenticationDefaults.AuthenticationScheme
|
||||
opts.DefaultSignInScheme <- CookieAuthenticationDefaults.AuthenticationScheme
|
||||
opts.DefaultChallengeScheme <- CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie()
|
||||
.AddOpenIdConnect("Auth0", fun opts ->
|
||||
// Configure OIDC with Auth0 options from configuration
|
||||
let cfg = bldr.Configuration.GetSection "Auth0"
|
||||
opts.Authority <- $"""https://{cfg["Domain"]}/"""
|
||||
opts.ClientId <- cfg["Id"]
|
||||
opts.ClientSecret <- cfg["Secret"]
|
||||
opts.ResponseType <- OpenIdConnectResponseType.Code
|
||||
|
||||
opts.Scope.Clear ()
|
||||
opts.Scope.Add "openid"
|
||||
opts.Scope.Add "profile"
|
||||
|
||||
opts.CallbackPath <- PathString "/user/log-on/success"
|
||||
opts.ClaimsIssuer <- "Auth0"
|
||||
opts.SaveTokens <- true
|
||||
|
||||
opts.Events <- OpenIdConnectEvents ()
|
||||
opts.Events.OnRedirectToIdentityProviderForSignOut <- fun ctx ->
|
||||
let returnTo =
|
||||
match ctx.Properties.RedirectUri with
|
||||
| it when isNull it || it = "" -> ""
|
||||
| redirUri ->
|
||||
let finalRedirUri =
|
||||
match redirUri.StartsWith "/" with
|
||||
| true ->
|
||||
// transform to absolute
|
||||
let request = ctx.Request
|
||||
$"{request.Scheme}://{request.Host.Value}{request.PathBase.Value}{redirUri}"
|
||||
| false -> redirUri
|
||||
Uri.EscapeDataString $"&returnTo={finalRedirUri}"
|
||||
ctx.Response.Redirect $"""https://{cfg["Domain"]}/v2/logout?client_id={cfg["Id"]}{returnTo}"""
|
||||
ctx.HandleResponse ()
|
||||
Task.CompletedTask
|
||||
opts.Events.OnRedirectToIdentityProvider <- fun ctx ->
|
||||
let bldr = UriBuilder ctx.ProtocolMessage.RedirectUri
|
||||
bldr.Scheme <- cfg["Scheme"]
|
||||
bldr.Port <- int cfg["Port"]
|
||||
ctx.ProtocolMessage.RedirectUri <- string bldr
|
||||
Task.CompletedTask)
|
||||
|
||||
let jsonOptions = JsonSerializerOptions ()
|
||||
jsonOptions.Converters.Add (JsonFSharpConverter ())
|
||||
let db = new LiteDatabase (bldr.Configuration.GetConnectionString "db")
|
||||
Data.Startup.ensureDb db
|
||||
let _ = bldr.Services.AddSingleton jsonOptions
|
||||
let _ = bldr.Services.AddSingleton<Json.ISerializer, SystemTextJson.Serializer> ()
|
||||
let _ = bldr.Services.AddSingleton<LiteDatabase> db
|
||||
|
||||
bldr.Build ()
|
||||
|
||||
|
||||
open Giraffe.EndpointRouting
|
||||
open Giraffe.EndpointRouting
|
||||
|
||||
/// Configure the web application
|
||||
let application (app : WebApplication) =
|
||||
// match app.Environment.IsDevelopment () with
|
||||
// | true -> app.UseDeveloperExceptionPage ()
|
||||
// | false -> app.UseGiraffeErrorHandler Handlers.Error.error
|
||||
// |> ignore
|
||||
app
|
||||
.UseStaticFiles()
|
||||
.UseCookiePolicy()
|
||||
.UseRouting()
|
||||
.UseAuthentication()
|
||||
.UseGiraffeErrorHandler(Handlers.Error.error)
|
||||
.UseEndpoints (fun e -> e.MapGiraffeEndpoints Handlers.routes |> ignore)
|
||||
|> ignore
|
||||
app
|
||||
/// Configure the web application
|
||||
let application (app : WebApplication) =
|
||||
let _ = app.UseStaticFiles ()
|
||||
let _ = app.UseCookiePolicy ()
|
||||
let _ = app.UseRouting ()
|
||||
let _ = app.UseAuthentication ()
|
||||
let _ = app.UseGiraffeErrorHandler Handlers.Error.error
|
||||
let _ = app.UseEndpoints (fun e -> e.MapGiraffeEndpoints Handlers.routes)
|
||||
app
|
||||
|
||||
/// Compose all the configurations into one
|
||||
let webHost pathSegments =
|
||||
contentRoot
|
||||
>> appConfiguration
|
||||
>> kestrel
|
||||
>> webRoot pathSegments
|
||||
>> logging
|
||||
>> services
|
||||
>> application
|
||||
/// Compose all the configurations into one
|
||||
let webHost pathSegments =
|
||||
contentRoot
|
||||
>> appConfiguration
|
||||
>> kestrel
|
||||
>> webRoot pathSegments
|
||||
>> logging
|
||||
>> services
|
||||
>> application
|
||||
|
||||
|
||||
[<EntryPoint>]
|
||||
let main _ =
|
||||
use host = Configure.webHost [| "wwwroot" |] (Directory.GetCurrentDirectory ())
|
||||
host.Run ()
|
||||
0
|
||||
use host = Configure.webHost [| "wwwroot" |] (Directory.GetCurrentDirectory ())
|
||||
host.Run ()
|
||||
0
|
||||
|
||||
Reference in New Issue
Block a user