Version 3 #67
@ -79,7 +79,6 @@ module Indexes =
|
|||||||
/// All data manipulations within myPrayerJournal
|
/// All data manipulations within myPrayerJournal
|
||||||
module Data =
|
module Data =
|
||||||
|
|
||||||
open FSharp.Control.Tasks.V2.ContextInsensitive
|
|
||||||
open Indexes
|
open Indexes
|
||||||
open Microsoft.FSharpLu
|
open Microsoft.FSharpLu
|
||||||
open Raven.Client.Documents
|
open Raven.Client.Documents
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
/// The data model for myPrayerJournal
|
/// The data model for myPrayerJournal
|
||||||
module MyPrayerJournal.Domain
|
module MyPrayerJournal.Domain
|
||||||
|
|
||||||
|
// fsharplint:disable RecordFieldNames
|
||||||
|
|
||||||
open Cuid
|
open Cuid
|
||||||
|
|
||||||
/// Request ID is a CUID
|
/// Request ID is a CUID
|
||||||
@ -9,9 +11,9 @@ type RequestId =
|
|||||||
| RequestId of Cuid
|
| RequestId of Cuid
|
||||||
module RequestId =
|
module RequestId =
|
||||||
/// The string representation of the request ID
|
/// The string representation of the request ID
|
||||||
let toString x = match x with RequestId y -> (Cuid.toString >> sprintf "Requests/%s") y
|
let toString = function RequestId x -> $"Requests/{Cuid.toString x}"
|
||||||
/// Create a request ID from a string representation
|
/// Create a request ID from a string representation
|
||||||
let fromIdString (y : string) = (Cuid >> RequestId) <| y.Replace("Requests/", "")
|
let fromIdString (x : string) = x.Replace ("Requests/", "") |> (Cuid >> RequestId)
|
||||||
|
|
||||||
|
|
||||||
/// User ID is a string (the "sub" part of the JWT)
|
/// User ID is a string (the "sub" part of the JWT)
|
||||||
@ -19,7 +21,7 @@ type UserId =
|
|||||||
| UserId of string
|
| UserId of string
|
||||||
module UserId =
|
module UserId =
|
||||||
/// The string representation of the user ID
|
/// The string representation of the user ID
|
||||||
let toString x = match x with UserId y -> y
|
let toString = function UserId x -> x
|
||||||
|
|
||||||
|
|
||||||
/// A long integer representing seconds since the epoch
|
/// A long integer representing seconds since the epoch
|
||||||
@ -27,7 +29,7 @@ type Ticks =
|
|||||||
| Ticks of int64
|
| Ticks of int64
|
||||||
module Ticks =
|
module Ticks =
|
||||||
/// The int64 (long) representation of ticks
|
/// The int64 (long) representation of ticks
|
||||||
let toLong x = match x with Ticks y -> y
|
let toLong = function Ticks x -> x
|
||||||
|
|
||||||
|
|
||||||
/// How frequently a request should reappear after it is marked "Prayed"
|
/// How frequently a request should reappear after it is marked "Prayed"
|
||||||
@ -38,16 +40,16 @@ type Recurrence =
|
|||||||
| Weeks
|
| Weeks
|
||||||
module Recurrence =
|
module Recurrence =
|
||||||
/// Create a recurrence value from a string
|
/// Create a recurrence value from a string
|
||||||
let fromString x =
|
let fromString =
|
||||||
match x with
|
function
|
||||||
| "Immediate" -> Immediate
|
| "Immediate" -> Immediate
|
||||||
| "Hours" -> Hours
|
| "Hours" -> Hours
|
||||||
| "Days" -> Days
|
| "Days" -> Days
|
||||||
| "Weeks" -> Weeks
|
| "Weeks" -> Weeks
|
||||||
| _ -> invalidOp (sprintf "%s is not a valid recurrence" x)
|
| it -> invalidOp $"{it} is not a valid recurrence"
|
||||||
/// The duration of the recurrence
|
/// The duration of the recurrence
|
||||||
let duration x =
|
let duration =
|
||||||
match x with
|
function
|
||||||
| Immediate -> 0L
|
| Immediate -> 0L
|
||||||
| Hours -> 3600000L
|
| Hours -> 3600000L
|
||||||
| Days -> 86400000L
|
| Days -> 86400000L
|
||||||
@ -62,13 +64,13 @@ type RequestAction =
|
|||||||
| Answered
|
| Answered
|
||||||
module RequestAction =
|
module RequestAction =
|
||||||
/// Create a RequestAction from a string
|
/// Create a RequestAction from a string
|
||||||
let fromString x =
|
let fromString =
|
||||||
match x with
|
function
|
||||||
| "Created" -> Created
|
| "Created" -> Created
|
||||||
| "Prayed" -> Prayed
|
| "Prayed" -> Prayed
|
||||||
| "Updated" -> Updated
|
| "Updated" -> Updated
|
||||||
| "Answered" -> Answered
|
| "Answered" -> Answered
|
||||||
| _ -> (sprintf "Bad request action %s" >> invalidOp) x
|
| it -> invalidOp $"Bad request action {it}"
|
||||||
|
|
||||||
|
|
||||||
/// History is a record of action taken on a prayer request, including updates to its text
|
/// History is a record of action taken on a prayer request, including updates to its text
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module MyPrayerJournal.Handlers
|
module MyPrayerJournal.Handlers
|
||||||
|
|
||||||
|
// fsharplint:disable RecordFieldNames
|
||||||
|
|
||||||
open Giraffe
|
open Giraffe
|
||||||
|
|
||||||
/// Handler to return Vue files
|
/// Handler to return Vue files
|
||||||
@ -60,11 +62,10 @@ module private Helpers =
|
|||||||
|
|
||||||
/// Create a request ID from a string
|
/// Create a request ID from a string
|
||||||
let toReqId x =
|
let toReqId x =
|
||||||
let reqId =
|
match Cuid.ofString x with
|
||||||
match Cuid.ofString x with
|
| Ok cuid -> cuid
|
||||||
| Ok cuid -> cuid
|
| Error msg -> invalidOp msg
|
||||||
| Error msg -> invalidOp msg
|
|> RequestId
|
||||||
RequestId reqId
|
|
||||||
|
|
||||||
/// Return a 201 CREATED response
|
/// Return a 201 CREATED response
|
||||||
let created next ctx =
|
let created next ctx =
|
||||||
@ -88,12 +89,12 @@ module private Helpers =
|
|||||||
|
|
||||||
/// Work-around to let the Json.NET serializer synchronously deserialize from the request stream
|
/// Work-around to let the Json.NET serializer synchronously deserialize from the request stream
|
||||||
// TODO: Remove this once there is an async serializer
|
// TODO: Remove this once there is an async serializer
|
||||||
let allowSyncIO : HttpHandler =
|
// let allowSyncIO : HttpHandler =
|
||||||
fun next ctx ->
|
// fun next ctx ->
|
||||||
match ctx.Features.Get<Features.IHttpBodyControlFeature>() with
|
// match ctx.Features.Get<Features.IHttpBodyControlFeature>() with
|
||||||
| null -> ()
|
// | null -> ()
|
||||||
| f -> f.AllowSynchronousIO <- true
|
// | f -> f.AllowSynchronousIO <- true
|
||||||
next ctx
|
// next ctx
|
||||||
|
|
||||||
|
|
||||||
/// Strongly-typed models for post requests
|
/// Strongly-typed models for post requests
|
||||||
@ -142,8 +143,6 @@ module Models =
|
|||||||
until : int64
|
until : int64
|
||||||
}
|
}
|
||||||
|
|
||||||
open FSharp.Control.Tasks.V2.ContextInsensitive
|
|
||||||
|
|
||||||
/// /api/journal URLs
|
/// /api/journal URLs
|
||||||
module Journal =
|
module Journal =
|
||||||
|
|
||||||
@ -165,7 +164,7 @@ module Request =
|
|||||||
/// POST /api/request
|
/// POST /api/request
|
||||||
let add : HttpHandler =
|
let add : HttpHandler =
|
||||||
authorize
|
authorize
|
||||||
>=> allowSyncIO
|
// >=> allowSyncIO
|
||||||
>=> fun next ctx ->
|
>=> fun next ctx ->
|
||||||
task {
|
task {
|
||||||
let! r = ctx.BindJsonAsync<Models.Request> ()
|
let! r = ctx.BindJsonAsync<Models.Request> ()
|
||||||
@ -197,7 +196,7 @@ module Request =
|
|||||||
/// POST /api/request/[req-id]/history
|
/// POST /api/request/[req-id]/history
|
||||||
let addHistory requestId : HttpHandler =
|
let addHistory requestId : HttpHandler =
|
||||||
authorize
|
authorize
|
||||||
>=> allowSyncIO
|
// >=> allowSyncIO
|
||||||
>=> fun next ctx ->
|
>=> fun next ctx ->
|
||||||
task {
|
task {
|
||||||
use sess = session ctx
|
use sess = session ctx
|
||||||
@ -229,7 +228,7 @@ module Request =
|
|||||||
/// POST /api/request/[req-id]/note
|
/// POST /api/request/[req-id]/note
|
||||||
let addNote requestId : HttpHandler =
|
let addNote requestId : HttpHandler =
|
||||||
authorize
|
authorize
|
||||||
>=> allowSyncIO
|
// >=> allowSyncIO
|
||||||
>=> fun next ctx ->
|
>=> fun next ctx ->
|
||||||
task {
|
task {
|
||||||
use sess = session ctx
|
use sess = session ctx
|
||||||
@ -309,7 +308,7 @@ module Request =
|
|||||||
/// PATCH /api/request/[req-id]/snooze
|
/// PATCH /api/request/[req-id]/snooze
|
||||||
let snooze requestId : HttpHandler =
|
let snooze requestId : HttpHandler =
|
||||||
authorize
|
authorize
|
||||||
>=> allowSyncIO
|
// >=> allowSyncIO
|
||||||
>=> fun next ctx ->
|
>=> fun next ctx ->
|
||||||
task {
|
task {
|
||||||
use sess = session ctx
|
use sess = session ctx
|
||||||
@ -327,7 +326,7 @@ module Request =
|
|||||||
/// PATCH /api/request/[req-id]/recurrence
|
/// PATCH /api/request/[req-id]/recurrence
|
||||||
let updateRecurrence requestId : HttpHandler =
|
let updateRecurrence requestId : HttpHandler =
|
||||||
authorize
|
authorize
|
||||||
>=> allowSyncIO
|
// >=> allowSyncIO
|
||||||
>=> fun next ctx ->
|
>=> fun next ctx ->
|
||||||
task {
|
task {
|
||||||
use sess = session ctx
|
use sess = session ctx
|
||||||
@ -344,12 +343,11 @@ module Request =
|
|||||||
| None -> return! Error.notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
open Giraffe.TokenRouter
|
open Giraffe.EndpointRouting
|
||||||
|
|
||||||
/// The routes for myPrayerJournal
|
/// The routes for myPrayerJournal
|
||||||
let webApp : HttpHandler =
|
let routes =
|
||||||
router Error.notFound [
|
[ route "/" Vue.app
|
||||||
route "/" Vue.app
|
|
||||||
subRoute "/api/" [
|
subRoute "/api/" [
|
||||||
GET [
|
GET [
|
||||||
route "journal" Journal.journal
|
route "journal" Journal.journal
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Version>3.0.0.0</Version>
|
<Version>3.0.0.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@ -14,17 +14,12 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FunctionalCuid" Version="1.0.0" />
|
<PackageReference Include="FunctionalCuid" Version="1.0.0" />
|
||||||
<PackageReference Include="Giraffe" Version="4.1.0" />
|
<PackageReference Include="Giraffe" Version="5.0.0" />
|
||||||
<PackageReference Include="Giraffe.TokenRouter" Version="1.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.10" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.3" />
|
<PackageReference Include="Microsoft.FSharpLu" Version="0.11.7" />
|
||||||
<PackageReference Include="Microsoft.FSharpLu" Version="0.11.6" />
|
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.11.7" />
|
||||||
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.11.6" />
|
|
||||||
<PackageReference Include="RavenDb.Client" Version="4.2.102" />
|
<PackageReference Include="RavenDb.Client" Version="4.2.102" />
|
||||||
<PackageReference Include="TaskBuilder.fs" Version="2.1.0" />
|
<PackageReference Include="RethinkDb.Driver" Version="2.3.150" />
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Update="FSharp.Core" Version="4.7.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -36,7 +36,6 @@ module Configure =
|
|||||||
(Path.Combine >> bldr.UseWebRoot) pathSegments
|
(Path.Combine >> bldr.UseWebRoot) pathSegments
|
||||||
|
|
||||||
open Giraffe
|
open Giraffe
|
||||||
open Giraffe.Serialization
|
|
||||||
open Microsoft.AspNetCore.Authentication.JwtBearer
|
open Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
open Microsoft.Extensions.DependencyInjection
|
open Microsoft.Extensions.DependencyInjection
|
||||||
open MyPrayerJournal.Indexes
|
open MyPrayerJournal.Indexes
|
||||||
@ -51,7 +50,7 @@ module Configure =
|
|||||||
let svcs (sc : IServiceCollection) =
|
let svcs (sc : IServiceCollection) =
|
||||||
/// Custom settings for the JSON serializer (uses compact representation for options and DUs)
|
/// Custom settings for the JSON serializer (uses compact representation for options and DUs)
|
||||||
let jsonSettings =
|
let jsonSettings =
|
||||||
let x = NewtonsoftJsonSerializer.DefaultSettings
|
let x = NewtonsoftJson.Serializer.DefaultSettings
|
||||||
Converters.all |> List.ofSeq |> List.iter x.Converters.Add
|
Converters.all |> List.ofSeq |> List.iter x.Converters.Add
|
||||||
x.NullValueHandling <- NullValueHandling.Ignore
|
x.NullValueHandling <- NullValueHandling.Ignore
|
||||||
x.MissingMemberHandling <- MissingMemberHandling.Error
|
x.MissingMemberHandling <- MissingMemberHandling.Error
|
||||||
@ -61,7 +60,8 @@ module Configure =
|
|||||||
|
|
||||||
use sp = sc.BuildServiceProvider ()
|
use sp = sc.BuildServiceProvider ()
|
||||||
let cfg = sp.GetRequiredService<IConfiguration> ()
|
let cfg = sp.GetRequiredService<IConfiguration> ()
|
||||||
sc.AddGiraffe()
|
sc.AddRouting()
|
||||||
|
.AddGiraffe()
|
||||||
.AddAuthentication(
|
.AddAuthentication(
|
||||||
/// Use HTTP "Bearer" authentication with JWTs
|
/// Use HTTP "Bearer" authentication with JWTs
|
||||||
fun opts ->
|
fun opts ->
|
||||||
@ -75,7 +75,7 @@ module Configure =
|
|||||||
opts.Audience <- jwtCfg.["Id"]
|
opts.Audience <- jwtCfg.["Id"]
|
||||||
)
|
)
|
||||||
|> ignore
|
|> ignore
|
||||||
sc.AddSingleton<IJsonSerializer> (NewtonsoftJsonSerializer jsonSettings)
|
sc.AddSingleton<Json.ISerializer> (NewtonsoftJson.Serializer jsonSettings)
|
||||||
|> ignore
|
|> ignore
|
||||||
let config = sc.BuildServiceProvider().GetRequiredService<IConfiguration>().GetSection "RavenDB"
|
let config = sc.BuildServiceProvider().GetRequiredService<IConfiguration>().GetSection "RavenDB"
|
||||||
let store = new DocumentStore ()
|
let store = new DocumentStore ()
|
||||||
@ -104,6 +104,7 @@ module Configure =
|
|||||||
bldr.ConfigureLogging logz
|
bldr.ConfigureLogging logz
|
||||||
|
|
||||||
open System
|
open System
|
||||||
|
open Giraffe.EndpointRouting
|
||||||
|
|
||||||
/// Configure the web application
|
/// Configure the web application
|
||||||
let application (bldr : IWebHostBuilder) =
|
let application (bldr : IWebHostBuilder) =
|
||||||
@ -118,7 +119,8 @@ module Configure =
|
|||||||
| a ->
|
| a ->
|
||||||
a.UseAuthentication()
|
a.UseAuthentication()
|
||||||
.UseStaticFiles()
|
.UseStaticFiles()
|
||||||
.UseGiraffe Handlers.webApp
|
.UseRouting()
|
||||||
|
.UseEndpoints (fun e -> e.MapGiraffeEndpoints Handlers.routes)
|
||||||
|> ignore)
|
|> ignore)
|
||||||
bldr.Configure appConfig
|
bldr.Configure appConfig
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user