WIP on NodaTime implementation

This commit is contained in:
Daniel J. Summers 2022-08-20 09:00:15 -04:00
parent 0b2a17d4c8
commit 80e7e26d51
16 changed files with 62 additions and 46 deletions

View File

@ -1,9 +1,9 @@
namespace MyWebLog.Data namespace MyWebLog.Data
open System
open System.Threading.Tasks open System.Threading.Tasks
open MyWebLog open MyWebLog
open MyWebLog.ViewModels open MyWebLog.ViewModels
open NodaTime
/// The result of a category deletion attempt /// The result of a category deletion attempt
type CategoryDeleteResult = type CategoryDeleteResult =
@ -137,7 +137,7 @@ type IPostData =
WebLogId -> tag : string -> pageNbr : int -> postsPerPage : int -> Task<Post list> WebLogId -> tag : string -> pageNbr : int -> postsPerPage : int -> Task<Post list>
/// Find the next older and newer post for the given published date/time (excluding revisions and prior permalinks) /// Find the next older and newer post for the given published date/time (excluding revisions and prior permalinks)
abstract member FindSurroundingPosts : WebLogId -> publishedOn : DateTime -> Task<Post option * Post option> abstract member FindSurroundingPosts : WebLogId -> publishedOn : Instant -> Task<Post option * Post option>
/// Restore posts from a backup /// Restore posts from a backup
abstract member Restore : Post list -> Task<unit> abstract member Restore : Post list -> Task<unit>

View File

@ -1,9 +1,9 @@
namespace MyWebLog.Data.Postgres namespace MyWebLog.Data.Postgres
open System
open MyWebLog open MyWebLog
open MyWebLog.Data open MyWebLog.Data
open Newtonsoft.Json open Newtonsoft.Json
open NodaTime
open Npgsql open Npgsql
open Npgsql.FSharp open Npgsql.FSharp
@ -238,11 +238,11 @@ type PostgresPostData (conn : NpgsqlConnection) =
|> Sql.executeAsync Map.toPost |> Sql.executeAsync Map.toPost
/// Find the next newest and oldest post from a publish date for the given web log /// Find the next newest and oldest post from a publish date for the given web log
let findSurroundingPosts webLogId (publishedOn : DateTime) = backgroundTask { let findSurroundingPosts webLogId (publishedOn : Instant) = backgroundTask {
let queryParams = Sql.parameters [ let queryParams = Sql.parameters [
webLogIdParam webLogId webLogIdParam webLogId
typedParam "@publishedOn" publishedOn
"@status", Sql.string (PostStatus.toString Published) "@status", Sql.string (PostStatus.toString Published)
"@publishedOn", Sql.timestamptz publishedOn
] ]
let! older = let! older =
Sql.existingConnection conn Sql.existingConnection conn

View File

@ -1,10 +1,10 @@
namespace MyWebLog.Data.SQLite namespace MyWebLog.Data.SQLite
open System
open System.Threading.Tasks open System.Threading.Tasks
open Microsoft.Data.Sqlite open Microsoft.Data.Sqlite
open MyWebLog open MyWebLog
open MyWebLog.Data open MyWebLog.Data
open NodaTime
/// SQLite myWebLog post data implementation /// SQLite myWebLog post data implementation
type SQLitePostData (conn : SqliteConnection) = type SQLitePostData (conn : SqliteConnection) =
@ -487,7 +487,7 @@ type SQLitePostData (conn : SqliteConnection) =
} }
/// Find the next newest and oldest post from a publish date for the given web log /// Find the next newest and oldest post from a publish date for the given web log
let findSurroundingPosts webLogId (publishedOn : DateTime) = backgroundTask { let findSurroundingPosts webLogId (publishedOn : Instant) = backgroundTask {
use cmd = conn.CreateCommand () use cmd = conn.CreateCommand ()
cmd.CommandText <- $" cmd.CommandText <- $"
{selectPost} {selectPost}
@ -498,7 +498,7 @@ type SQLitePostData (conn : SqliteConnection) =
LIMIT 1" LIMIT 1"
addWebLogId cmd webLogId addWebLogId cmd webLogId
[ cmd.Parameters.AddWithValue ("@status", PostStatus.toString Published) [ cmd.Parameters.AddWithValue ("@status", PostStatus.toString Published)
cmd.Parameters.AddWithValue ("@publishedOn", publishedOn) cmd.Parameters.AddWithValue ("@publishedOn", instantParam publishedOn)
] |> ignore ] |> ignore
use! rdr = cmd.ExecuteReaderAsync () use! rdr = cmd.ExecuteReaderAsync ()
let! older = backgroundTask { let! older = backgroundTask {

View File

@ -138,6 +138,8 @@ module ExplicitRating =
| x -> raise (invalidArg "rating" $"{x} is not a valid explicit rating") | x -> raise (invalidArg "rating" $"{x} is not a valid explicit rating")
open NodaTime.Text
/// A podcast episode /// A podcast episode
type Episode = type Episode =
{ /// The URL to the media file for the episode (may be permalink) { /// The URL to the media file for the episode (may be permalink)
@ -216,6 +218,10 @@ module Episode =
EpisodeDescription = None EpisodeDescription = None
} }
/// Format a duration for an episode
let formatDuration ep =
ep.Duration |> Option.map (DurationPattern.CreateWithInvariantCulture("H:mm:ss").Format)
open Markdig open Markdig
open Markdown.ColorCode open Markdown.ColorCode

View File

@ -3,7 +3,6 @@
open System open System
open MyWebLog open MyWebLog
open NodaTime open NodaTime
open NodaTime.Text
/// Helper functions for view models /// Helper functions for view models
[<AutoOpen>] [<AutoOpen>]
@ -706,7 +705,6 @@ type EditPostModel =
| Some rev -> rev | Some rev -> rev
| None -> Revision.empty | None -> Revision.empty
let post = if post.Metadata |> List.isEmpty then { post with Metadata = [ MetaItem.empty ] } else post let post = if post.Metadata |> List.isEmpty then { post with Metadata = [ MetaItem.empty ] } else post
let format = DurationPattern.CreateWithInvariantCulture("H:mm:ss").Format
let episode = defaultArg post.Episode Episode.empty let episode = defaultArg post.Episode Episode.empty
{ PostId = PostId.toString post.Id { PostId = PostId.toString post.Id
Title = post.Title Title = post.Title
@ -726,7 +724,7 @@ type EditPostModel =
IsEpisode = Option.isSome post.Episode IsEpisode = Option.isSome post.Episode
Media = episode.Media Media = episode.Media
Length = episode.Length Length = episode.Length
Duration = defaultArg (episode.Duration |> Option.map format) "" Duration = defaultArg (Episode.formatDuration episode) ""
MediaType = defaultArg episode.MediaType "" MediaType = defaultArg episode.MediaType ""
ImageUrl = defaultArg episode.ImageUrl "" ImageUrl = defaultArg episode.ImageUrl ""
Subtitle = defaultArg episode.Subtitle "" Subtitle = defaultArg episode.Subtitle ""

View File

@ -11,6 +11,7 @@ module Extensions =
open Microsoft.AspNetCore.Antiforgery open Microsoft.AspNetCore.Antiforgery
open Microsoft.Extensions.Configuration open Microsoft.Extensions.Configuration
open Microsoft.Extensions.DependencyInjection open Microsoft.Extensions.DependencyInjection
open NodaTime
/// Hold variable for the configured generator string /// Hold variable for the configured generator string
let mutable private generatorString : string option = None let mutable private generatorString : string option = None
@ -20,6 +21,9 @@ module Extensions =
/// The anti-CSRF service /// The anti-CSRF service
member this.AntiForgery = this.RequestServices.GetRequiredService<IAntiforgery> () member this.AntiForgery = this.RequestServices.GetRequiredService<IAntiforgery> ()
/// The system clock
member this.Clock = this.RequestServices.GetRequiredService<IClock> ()
/// The cross-site request forgery token set for this request /// The cross-site request forgery token set for this request
member this.CsrfTokenSet = this.AntiForgery.GetAndStoreTokens this member this.CsrfTokenSet = this.AntiForgery.GetAndStoreTokens this

View File

@ -5,6 +5,7 @@ open System.Threading.Tasks
open Giraffe open Giraffe
open MyWebLog open MyWebLog
open MyWebLog.ViewModels open MyWebLog.ViewModels
open NodaTime
/// ~~ DASHBOARDS ~~ /// ~~ DASHBOARDS ~~
module Dashboard = module Dashboard =
@ -344,7 +345,8 @@ module Theme =
do! asset.Open().CopyToAsync stream do! asset.Open().CopyToAsync stream
do! data.ThemeAsset.Save do! data.ThemeAsset.Save
{ Id = ThemeAssetId (themeId, assetName) { Id = ThemeAssetId (themeId, assetName)
UpdatedOn = asset.LastWriteTime.DateTime UpdatedOn = LocalDateTime.FromDateTime(asset.LastWriteTime.DateTime)
.InZoneLeniently(DateTimeZone.Utc).ToInstant ()
Data = stream.ToArray () Data = stream.ToArray ()
} }
} }

View File

@ -95,8 +95,8 @@ let private toFeedItem webLog (authors : MetaItem list) (cats : DisplayCategory[
let item = SyndicationItem ( let item = SyndicationItem (
Id = WebLog.absoluteUrl webLog post.Permalink, Id = WebLog.absoluteUrl webLog post.Permalink,
Title = TextSyndicationContent.CreateHtmlContent post.Title, Title = TextSyndicationContent.CreateHtmlContent post.Title,
PublishDate = DateTimeOffset post.PublishedOn.Value, PublishDate = post.PublishedOn.Value.ToDateTimeOffset (),
LastUpdatedTime = DateTimeOffset post.UpdatedOn, LastUpdatedTime = post.UpdatedOn.ToDateTimeOffset (),
Content = TextSyndicationContent.CreatePlaintextContent plainText) Content = TextSyndicationContent.CreatePlaintextContent plainText)
item.AddPermalink (Uri item.Id) item.AddPermalink (Uri item.Id)
@ -163,8 +163,8 @@ let private addEpisode webLog (podcast : PodcastOptions) (episode : Episode) (po
item.ElementExtensions.Add ("author", Namespace.iTunes, podcast.DisplayedAuthor) item.ElementExtensions.Add ("author", Namespace.iTunes, podcast.DisplayedAuthor)
item.ElementExtensions.Add ("explicit", Namespace.iTunes, epExplicit) item.ElementExtensions.Add ("explicit", Namespace.iTunes, epExplicit)
episode.Subtitle |> Option.iter (fun it -> item.ElementExtensions.Add ("subtitle", Namespace.iTunes, it)) episode.Subtitle |> Option.iter (fun it -> item.ElementExtensions.Add ("subtitle", Namespace.iTunes, it))
episode.Duration Episode.formatDuration episode
|> Option.iter (fun it -> item.ElementExtensions.Add ("duration", Namespace.iTunes, it.ToString """hh\:mm\:ss""")) |> Option.iter (fun it -> item.ElementExtensions.Add ("duration", Namespace.iTunes, it))
match episode.ChapterFile with match episode.ChapterFile with
| Some chapters -> | Some chapters ->
@ -381,7 +381,7 @@ let createFeed (feedType : FeedType) posts : HttpHandler = fun next ctx -> backg
addNamespace feed "content" Namespace.content addNamespace feed "content" Namespace.content
setTitleAndDescription feedType webLog cats feed setTitleAndDescription feedType webLog cats feed
feed.LastUpdatedTime <- (List.head posts).UpdatedOn |> DateTimeOffset feed.LastUpdatedTime <- (List.head posts).UpdatedOn.ToDateTimeOffset ()
feed.Generator <- ctx.Generator feed.Generator <- ctx.Generator
feed.Items <- posts |> Seq.ofList |> Seq.map toItem feed.Items <- posts |> Seq.ofList |> Seq.map toItem
feed.Language <- "en" feed.Language <- "en"

View File

@ -419,10 +419,11 @@ let getCategoryIds slug ctx =
open System open System
open System.Globalization open System.Globalization
open NodaTime
/// Parse a date/time to UTC /// Parse a date/time to UTC
let parseToUtc (date : string) = let parseToUtc (date : string) =
DateTime.Parse (date, null, DateTimeStyles.AdjustToUniversal) Instant.FromDateTimeUtc (DateTime.Parse (date, null, DateTimeStyles.AdjustToUniversal))
open Microsoft.Extensions.DependencyInjection open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Logging open Microsoft.Extensions.Logging

View File

@ -139,15 +139,13 @@ let previewRevision (pgId, revDate) : HttpHandler = requireAccess Author >=> fun
| _, None -> return! Error.notFound next ctx | _, None -> return! Error.notFound next ctx
} }
open System
// POST /admin/page/{id}/revision/{revision-date}/restore // POST /admin/page/{id}/revision/{revision-date}/restore
let restoreRevision (pgId, revDate) : HttpHandler = requireAccess Author >=> fun next ctx -> task { let restoreRevision (pgId, revDate) : HttpHandler = requireAccess Author >=> fun next ctx -> task {
match! findPageRevision pgId revDate ctx with match! findPageRevision pgId revDate ctx with
| Some pg, Some rev when canEdit pg.AuthorId ctx -> | Some pg, Some rev when canEdit pg.AuthorId ctx ->
do! ctx.Data.Page.Update do! ctx.Data.Page.Update
{ pg with { pg with
Revisions = { rev with AsOf = DateTime.UtcNow } Revisions = { rev with AsOf = ctx.Clock.GetCurrentInstant () }
:: (pg.Revisions |> List.filter (fun r -> r.AsOf <> rev.AsOf)) :: (pg.Revisions |> List.filter (fun r -> r.AsOf <> rev.AsOf))
} }
do! addMessage ctx { UserMessage.success with Message = "Revision restored successfully" } do! addMessage ctx { UserMessage.success with Message = "Revision restored successfully" }
@ -173,7 +171,7 @@ let deleteRevision (pgId, revDate) : HttpHandler = requireAccess Author >=> fun
let save : HttpHandler = requireAccess Author >=> fun next ctx -> task { let save : HttpHandler = requireAccess Author >=> fun next ctx -> task {
let! model = ctx.BindFormAsync<EditPageModel> () let! model = ctx.BindFormAsync<EditPageModel> ()
let data = ctx.Data let data = ctx.Data
let now = DateTime.UtcNow let now = ctx.Clock.GetCurrentInstant ()
let tryPage = let tryPage =
if model.IsNew then if model.IsNew then
{ Page.empty with { Page.empty with

View File

@ -53,8 +53,8 @@ let preparePostList webLog posts listType (url : string) pageNbr perPage (data :
match listType with match listType with
| SinglePost -> | SinglePost ->
let post = List.head posts let post = List.head posts
let dateTime = defaultArg post.PublishedOn post.UpdatedOn let target = defaultArg post.PublishedOn post.UpdatedOn
data.Post.FindSurroundingPosts webLog.Id dateTime data.Post.FindSurroundingPosts webLog.Id target
| _ -> Task.FromResult (None, None) | _ -> Task.FromResult (None, None)
let newerLink = let newerLink =
match listType, pageNbr with match listType, pageNbr with
@ -350,7 +350,7 @@ let restoreRevision (postId, revDate) : HttpHandler = requireAccess Author >=> f
| Some post, Some rev when canEdit post.AuthorId ctx -> | Some post, Some rev when canEdit post.AuthorId ctx ->
do! ctx.Data.Post.Update do! ctx.Data.Post.Update
{ post with { post with
Revisions = { rev with AsOf = DateTime.UtcNow } Revisions = { rev with AsOf = ctx.Clock.GetCurrentInstant () }
:: (post.Revisions |> List.filter (fun r -> r.AsOf <> rev.AsOf)) :: (post.Revisions |> List.filter (fun r -> r.AsOf <> rev.AsOf))
} }
do! addMessage ctx { UserMessage.success with Message = "Revision restored successfully" } do! addMessage ctx { UserMessage.success with Message = "Revision restored successfully" }
@ -376,7 +376,6 @@ let deleteRevision (postId, revDate) : HttpHandler = requireAccess Author >=> fu
let save : HttpHandler = requireAccess Author >=> fun next ctx -> task { let save : HttpHandler = requireAccess Author >=> fun next ctx -> task {
let! model = ctx.BindFormAsync<EditPostModel> () let! model = ctx.BindFormAsync<EditPostModel> ()
let data = ctx.Data let data = ctx.Data
let now = DateTime.UtcNow
let tryPost = let tryPost =
if model.IsNew then if model.IsNew then
{ Post.empty with { Post.empty with
@ -389,7 +388,7 @@ let save : HttpHandler = requireAccess Author >=> fun next ctx -> task {
| Some post when canEdit post.AuthorId ctx -> | Some post when canEdit post.AuthorId ctx ->
let priorCats = post.CategoryIds let priorCats = post.CategoryIds
let updatedPost = let updatedPost =
model.UpdatePost post now model.UpdatePost post (ctx.Clock.GetCurrentInstant ())
|> function |> function
| post -> | post ->
if model.SetPublished then if model.SetPublished then

View File

@ -94,7 +94,7 @@ module Asset =
| Some asset -> | Some asset ->
match Upload.checkModified asset.UpdatedOn ctx with match Upload.checkModified asset.UpdatedOn ctx with
| Some threeOhFour -> return! threeOhFour next ctx | Some threeOhFour -> return! threeOhFour next ctx
| None -> return! Upload.sendFile asset.UpdatedOn path asset.Data next ctx | None -> return! Upload.sendFile (asset.UpdatedOn.ToDateTimeUtc ()) path asset.Data next ctx
| None -> return! Error.notFound next ctx | None -> return! Error.notFound next ctx
} }

View File

@ -29,15 +29,17 @@ module private Helpers =
// ~~ SERVING UPLOADS ~~ // ~~ SERVING UPLOADS ~~
open System.Globalization
open Giraffe open Giraffe
open Microsoft.AspNetCore.Http open Microsoft.AspNetCore.Http
open NodaTime
/// Determine if the file has been modified since the date/time specified by the If-Modified-Since header /// Determine if the file has been modified since the date/time specified by the If-Modified-Since header
let checkModified since (ctx : HttpContext) : HttpHandler option = let checkModified since (ctx : HttpContext) : HttpHandler option =
match ctx.Request.Headers.IfModifiedSince with match ctx.Request.Headers.IfModifiedSince with
| it when it.Count < 1 -> None | it when it.Count < 1 -> None
| it when since > DateTime.Parse it[0] -> None | it when since > Instant.FromDateTimeUtc (DateTime.Parse (it[0], null, DateTimeStyles.AdjustToUniversal)) -> None
| _ -> Some (setStatusCode 304 >=> setBodyFromString "Not Modified") | _ -> Some (setStatusCode 304)
open Microsoft.AspNetCore.Http.Headers open Microsoft.AspNetCore.Http.Headers
@ -73,7 +75,7 @@ let serve (urlParts : string seq) : HttpHandler = fun next ctx -> task {
| Some upload -> | Some upload ->
match checkModified upload.UpdatedOn ctx with match checkModified upload.UpdatedOn ctx with
| Some threeOhFour -> return! threeOhFour next ctx | Some threeOhFour -> return! threeOhFour next ctx
| None -> return! sendFile upload.UpdatedOn path upload.Data next ctx | None -> return! sendFile (upload.UpdatedOn.ToDateTimeUtc ()) path upload.Data next ctx
| None -> return! Error.notFound next ctx | None -> return! Error.notFound next ctx
else else
return! Error.notFound next ctx return! Error.notFound next ctx
@ -143,7 +145,8 @@ let save : HttpHandler = requireAccess Author >=> fun next ctx -> task {
let upload = Seq.head ctx.Request.Form.Files let upload = Seq.head ctx.Request.Form.Files
let fileName = String.Concat (makeSlug (Path.GetFileNameWithoutExtension upload.FileName), let fileName = String.Concat (makeSlug (Path.GetFileNameWithoutExtension upload.FileName),
Path.GetExtension(upload.FileName).ToLowerInvariant ()) Path.GetExtension(upload.FileName).ToLowerInvariant ())
let localNow = WebLog.localTime ctx.WebLog DateTime.Now let now = ctx.Clock.GetCurrentInstant ()
let localNow = WebLog.localTime ctx.WebLog now
let year = localNow.ToString "yyyy" let year = localNow.ToString "yyyy"
let month = localNow.ToString "MM" let month = localNow.ToString "MM"
let! form = ctx.BindFormAsync<UploadFileModel> () let! form = ctx.BindFormAsync<UploadFileModel> ()
@ -156,7 +159,7 @@ let save : HttpHandler = requireAccess Author >=> fun next ctx -> task {
{ Id = UploadId.create () { Id = UploadId.create ()
WebLogId = ctx.WebLog.Id WebLogId = ctx.WebLog.Id
Path = Permalink $"{year}/{month}/{fileName}" Path = Permalink $"{year}/{month}/{fileName}"
UpdatedOn = DateTime.UtcNow UpdatedOn = now
Data = stream.ToArray () Data = stream.ToArray ()
} }
do! ctx.Data.Upload.Add file do! ctx.Data.Upload.Add file

View File

@ -4,6 +4,7 @@ module MyWebLog.Handlers.User
open System open System
open System.Security.Cryptography open System.Security.Cryptography
open System.Text open System.Text
open NodaTime
// ~~ LOG ON / LOG OFF ~~ // ~~ LOG ON / LOG OFF ~~
@ -147,7 +148,9 @@ let private showMyInfo (model : EditMyInfoModel) (user : WebLogUser) : HttpHandl
|> addToHash ViewContext.Model model |> addToHash ViewContext.Model model
|> addToHash "access_level" (AccessLevel.toString user.AccessLevel) |> addToHash "access_level" (AccessLevel.toString user.AccessLevel)
|> addToHash "created_on" (WebLog.localTime ctx.WebLog user.CreatedOn) |> addToHash "created_on" (WebLog.localTime ctx.WebLog user.CreatedOn)
|> addToHash "last_seen_on" (WebLog.localTime ctx.WebLog (defaultArg user.LastSeenOn DateTime.UnixEpoch)) |> addToHash "last_seen_on" (WebLog.localTime ctx.WebLog
(defaultArg user.LastSeenOn (Instant.FromUnixTimeSeconds 0)))
|> adminView "my-info" next ctx |> adminView "my-info" next ctx
@ -200,7 +203,7 @@ let save : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task {
{ WebLogUser.empty with { WebLogUser.empty with
Id = WebLogUserId.create () Id = WebLogUserId.create ()
WebLogId = ctx.WebLog.Id WebLogId = ctx.WebLog.Id
CreatedOn = DateTime.UtcNow CreatedOn = ctx.Clock.GetCurrentInstant ()
} |> someTask } |> someTask
else data.WebLogUser.FindById (WebLogUserId model.Id) ctx.WebLog.Id else data.WebLogUser.FindById (WebLogUserId model.Id) ctx.WebLog.Id
match! tryUser with match! tryUser with
@ -227,4 +230,3 @@ let save : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task {
next ctx next ctx
| None -> return! Error.notFound next ctx | None -> return! Error.notFound next ctx
} }

View File

@ -4,6 +4,7 @@ open System
open System.IO open System.IO
open Microsoft.Extensions.DependencyInjection open Microsoft.Extensions.DependencyInjection
open MyWebLog.Data open MyWebLog.Data
open NodaTime
/// Create the web log information /// Create the web log information
let private doCreateWebLog (args : string[]) (sp : IServiceProvider) = task { let private doCreateWebLog (args : string[]) (sp : IServiceProvider) = task {
@ -42,7 +43,7 @@ let private doCreateWebLog (args : string[]) (sp : IServiceProvider) = task {
// Create the admin user // Create the admin user
let salt = Guid.NewGuid () let salt = Guid.NewGuid ()
let now = DateTime.UtcNow let now = SystemClock.Instance.GetCurrentInstant ()
do! data.WebLogUser.Add do! data.WebLogUser.Add
{ WebLogUser.empty with { WebLogUser.empty with
@ -165,7 +166,7 @@ module Backup =
Id : ThemeAssetId Id : ThemeAssetId
/// The updated date for this asset /// The updated date for this asset
UpdatedOn : DateTime UpdatedOn : Instant
/// The data for this asset, base-64 encoded /// The data for this asset, base-64 encoded
Data : string Data : string
@ -197,7 +198,7 @@ module Backup =
Path : Permalink Path : Permalink
/// The date/time this upload was last updated (file time) /// The date/time this upload was last updated (file time)
UpdatedOn : DateTime UpdatedOn : Instant
/// The data for the upload, base-64 encoded /// The data for the upload, base-64 encoded
Data : string Data : string

View File

@ -3,8 +3,6 @@ open Microsoft.Data.Sqlite
open Microsoft.Extensions.Configuration open Microsoft.Extensions.Configuration
open Microsoft.Extensions.Logging open Microsoft.Extensions.Logging
open MyWebLog open MyWebLog
open Newtonsoft.Json
open Npgsql
/// Middleware to derive the current web log /// Middleware to derive the current web log
type WebLogMiddleware (next : RequestDelegate, log : ILogger<WebLogMiddleware>) = type WebLogMiddleware (next : RequestDelegate, log : ILogger<WebLogMiddleware>) =
@ -31,6 +29,9 @@ type WebLogMiddleware (next : RequestDelegate, log : ILogger<WebLogMiddleware>)
open System open System
open Microsoft.Extensions.DependencyInjection open Microsoft.Extensions.DependencyInjection
open MyWebLog.Data open MyWebLog.Data
open Newtonsoft.Json
open NodaTime
open Npgsql
/// Logic to obtain a data connection and implementation based on configured values /// Logic to obtain a data connection and implementation based on configured values
module DataImplementation = module DataImplementation =
@ -119,6 +120,7 @@ let rec main args =
let sp = builder.Services.BuildServiceProvider () let sp = builder.Services.BuildServiceProvider ()
let data, serializer = DataImplementation.get sp let data, serializer = DataImplementation.get sp
let _ = builder.Services.AddSingleton<JsonSerializer> serializer let _ = builder.Services.AddSingleton<JsonSerializer> serializer
let _ = builder.Services.AddSingleton<IClock> SystemClock.Instance
task { task {
do! data.StartUp () do! data.StartUp ()