Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f289bee79d | |||
| f8cdd393ff | |||
| e3f3baa13f | |||
| 26fc214f36 | |||
| ce30af17fe |
@@ -1,12 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {}
|
||||||
"fake-cli": {
|
|
||||||
"version": "5.23.0",
|
|
||||||
"commands": [
|
|
||||||
"fake"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,9 +1,7 @@
|
|||||||
.ionide
|
.ionide
|
||||||
.fake
|
|
||||||
.idea
|
.idea
|
||||||
src/**/bin
|
src/**/bin
|
||||||
src/**/obj
|
src/**/obj
|
||||||
src/**/appsettings.*.json
|
src/**/appsettings.*.json
|
||||||
src/.vs
|
src/.vs
|
||||||
src/.idea
|
src/.idea
|
||||||
src/JobsJobsJobs/JobsJobsJobs.V3Migration/appsettings.json
|
|
||||||
|
|||||||
78
build.fsx
78
build.fsx
@@ -1,78 +0,0 @@
|
|||||||
#r "paket:
|
|
||||||
nuget Fake.DotNet.Cli
|
|
||||||
nuget Fake.IO.FileSystem
|
|
||||||
nuget Fake.JavaScript.Npm
|
|
||||||
nuget Fake.Core.Target //"
|
|
||||||
#load ".fake/build.fsx/intellisense.fsx"
|
|
||||||
open Fake.Core
|
|
||||||
open Fake.DotNet
|
|
||||||
open Fake.IO
|
|
||||||
open Fake.IO.Globbing.Operators
|
|
||||||
open Fake.JavaScript
|
|
||||||
open Fake.Core.TargetOperators
|
|
||||||
|
|
||||||
/// The path to the Vue client
|
|
||||||
let clientPath = "src/JobsJobsJobs/App"
|
|
||||||
|
|
||||||
/// The path to the API server
|
|
||||||
let serverPath = "src/JobsJobsJobs/Server"
|
|
||||||
|
|
||||||
Target.initEnvironment ()
|
|
||||||
|
|
||||||
Target.create "Clean" (fun _ ->
|
|
||||||
!! "src/**/bin"
|
|
||||||
++ "src/**/obj"
|
|
||||||
++ $"{serverPath}/wwwroot"
|
|
||||||
|> Shell.cleanDirs
|
|
||||||
)
|
|
||||||
|
|
||||||
Target.create "BuildClient" (fun _ ->
|
|
||||||
let inClientPath (opts : Npm.NpmParams) = { opts with WorkingDirectory = clientPath; }
|
|
||||||
Npm.exec "i --legacy-peer-deps" inClientPath
|
|
||||||
Npm.run "build" inClientPath
|
|
||||||
)
|
|
||||||
|
|
||||||
Target.create "BuildServer" (fun _ ->
|
|
||||||
DotNet.build (fun opts -> { opts with NoLogo = true }) serverPath
|
|
||||||
)
|
|
||||||
|
|
||||||
Target.create "RunServer" (fun _ ->
|
|
||||||
DotNet.exec (fun opts -> { opts with WorkingDirectory = serverPath }) "run" "" |> ignore
|
|
||||||
)
|
|
||||||
|
|
||||||
Target.create "Publish" (fun _ ->
|
|
||||||
DotNet.publish
|
|
||||||
(fun opts -> { opts with Runtime = Some "linux-x64"; SelfContained = Some false; NoLogo = true })
|
|
||||||
serverPath
|
|
||||||
)
|
|
||||||
|
|
||||||
Target.create "BuildAndRun" ignore
|
|
||||||
Target.create "All" ignore
|
|
||||||
|
|
||||||
"Clean"
|
|
||||||
==> "All"
|
|
||||||
"Clean"
|
|
||||||
==> "Publish"
|
|
||||||
"Clean"
|
|
||||||
?=> "BuildClient"
|
|
||||||
"Clean"
|
|
||||||
==> "BuildAndRun"
|
|
||||||
|
|
||||||
"BuildClient"
|
|
||||||
==> "All"
|
|
||||||
"BuildClient"
|
|
||||||
?=> "BuildServer"
|
|
||||||
"BuildClient"
|
|
||||||
?=> "RunServer"
|
|
||||||
"BuildClient"
|
|
||||||
==> "BuildAndRun"
|
|
||||||
"BuildClient"
|
|
||||||
==> "Publish"
|
|
||||||
|
|
||||||
"BuildServer"
|
|
||||||
==> "All"
|
|
||||||
|
|
||||||
"RunServer"
|
|
||||||
==> "BuildAndRun"
|
|
||||||
|
|
||||||
Target.runOrDefault "All"
|
|
||||||
231
build.fsx.lock
231
build.fsx.lock
@@ -1,231 +0,0 @@
|
|||||||
STORAGE: NONE
|
|
||||||
RESTRICTION: || (== net6.0) (== netstandard2.0)
|
|
||||||
NUGET
|
|
||||||
remote: https://api.nuget.org/v3/index.json
|
|
||||||
BlackFox.VsWhere (1.1)
|
|
||||||
FSharp.Core (>= 4.2.3)
|
|
||||||
Microsoft.Win32.Registry (>= 4.7)
|
|
||||||
Fake.Core.CommandLineParsing (5.23)
|
|
||||||
FParsec (>= 1.1.1)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.Context (5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.Environment (5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.FakeVar (5.23)
|
|
||||||
Fake.Core.Context (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.Process (5.23)
|
|
||||||
Fake.Core.Environment (>= 5.23)
|
|
||||||
Fake.Core.FakeVar (>= 5.23)
|
|
||||||
Fake.Core.String (>= 5.23)
|
|
||||||
Fake.Core.Trace (>= 5.23)
|
|
||||||
Fake.IO.FileSystem (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
System.Collections.Immutable (>= 5.0)
|
|
||||||
Fake.Core.SemVer (5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.String (5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.Target (5.23)
|
|
||||||
Fake.Core.CommandLineParsing (>= 5.23)
|
|
||||||
Fake.Core.Context (>= 5.23)
|
|
||||||
Fake.Core.Environment (>= 5.23)
|
|
||||||
Fake.Core.FakeVar (>= 5.23)
|
|
||||||
Fake.Core.Process (>= 5.23)
|
|
||||||
Fake.Core.String (>= 5.23)
|
|
||||||
Fake.Core.Trace (>= 5.23)
|
|
||||||
FSharp.Control.Reactive (>= 5.0.2)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.Tasks (5.23)
|
|
||||||
Fake.Core.Trace (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.Trace (5.23)
|
|
||||||
Fake.Core.Environment (>= 5.23)
|
|
||||||
Fake.Core.FakeVar (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Core.Xml (5.23)
|
|
||||||
Fake.Core.String (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.DotNet.Cli (5.23)
|
|
||||||
Fake.Core.Environment (>= 5.23)
|
|
||||||
Fake.Core.Process (>= 5.23)
|
|
||||||
Fake.Core.String (>= 5.23)
|
|
||||||
Fake.Core.Trace (>= 5.23)
|
|
||||||
Fake.DotNet.MSBuild (>= 5.23)
|
|
||||||
Fake.DotNet.NuGet (>= 5.23)
|
|
||||||
Fake.IO.FileSystem (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Mono.Posix.NETStandard (>= 1.0)
|
|
||||||
Newtonsoft.Json (>= 13.0.1)
|
|
||||||
Fake.DotNet.MSBuild (5.23)
|
|
||||||
BlackFox.VsWhere (>= 1.1)
|
|
||||||
Fake.Core.Environment (>= 5.23)
|
|
||||||
Fake.Core.Process (>= 5.23)
|
|
||||||
Fake.Core.String (>= 5.23)
|
|
||||||
Fake.Core.Trace (>= 5.23)
|
|
||||||
Fake.IO.FileSystem (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
MSBuild.StructuredLogger (>= 2.1.545)
|
|
||||||
Fake.DotNet.NuGet (5.23)
|
|
||||||
Fake.Core.Environment (>= 5.23)
|
|
||||||
Fake.Core.Process (>= 5.23)
|
|
||||||
Fake.Core.SemVer (>= 5.23)
|
|
||||||
Fake.Core.String (>= 5.23)
|
|
||||||
Fake.Core.Tasks (>= 5.23)
|
|
||||||
Fake.Core.Trace (>= 5.23)
|
|
||||||
Fake.Core.Xml (>= 5.23)
|
|
||||||
Fake.IO.FileSystem (>= 5.23)
|
|
||||||
Fake.Net.Http (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Newtonsoft.Json (>= 13.0.1)
|
|
||||||
NuGet.Protocol (>= 5.11)
|
|
||||||
Fake.IO.FileSystem (5.23)
|
|
||||||
Fake.Core.String (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.JavaScript.Npm (5.23)
|
|
||||||
Fake.Core.Environment (>= 5.23)
|
|
||||||
Fake.Core.Process (>= 5.23)
|
|
||||||
Fake.IO.FileSystem (>= 5.23)
|
|
||||||
Fake.Testing.Common (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Net.Http (5.23)
|
|
||||||
Fake.Core.Trace (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
Fake.Testing.Common (5.23)
|
|
||||||
Fake.Core.Trace (>= 5.23)
|
|
||||||
FSharp.Core (>= 6.0)
|
|
||||||
FParsec (1.1.1)
|
|
||||||
FSharp.Core (>= 4.3.4)
|
|
||||||
FSharp.Control.Reactive (5.0.5)
|
|
||||||
FSharp.Core (>= 4.7.2)
|
|
||||||
System.Reactive (>= 5.0 < 6.0)
|
|
||||||
FSharp.Core (6.0.5)
|
|
||||||
Microsoft.Build (17.2)
|
|
||||||
Microsoft.Build.Framework (>= 17.2) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
Microsoft.NET.StringTools (>= 1.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
Microsoft.Win32.Registry (>= 4.3) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Collections.Immutable (>= 5.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Configuration.ConfigurationManager (>= 4.7) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Reflection.Metadata (>= 1.6) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Security.Principal.Windows (>= 4.7) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Text.Encoding.CodePages (>= 4.0.1) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Text.Json (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Threading.Tasks.Dataflow (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
Microsoft.Build.Framework (17.3.1)
|
|
||||||
System.Security.Permissions (>= 6.0)
|
|
||||||
Microsoft.Build.Tasks.Core (17.2)
|
|
||||||
Microsoft.Build.Framework (>= 17.2)
|
|
||||||
Microsoft.Build.Utilities.Core (>= 17.2)
|
|
||||||
Microsoft.NET.StringTools (>= 1.0)
|
|
||||||
Microsoft.Win32.Registry (>= 4.3)
|
|
||||||
System.CodeDom (>= 4.4)
|
|
||||||
System.Collections.Immutable (>= 5.0)
|
|
||||||
System.Reflection.Metadata (>= 1.6)
|
|
||||||
System.Resources.Extensions (>= 4.6)
|
|
||||||
System.Security.Cryptography.Pkcs (>= 4.7)
|
|
||||||
System.Security.Cryptography.Xml (>= 4.7)
|
|
||||||
System.Security.Permissions (>= 4.7)
|
|
||||||
System.Threading.Tasks.Dataflow (>= 6.0)
|
|
||||||
Microsoft.Build.Utilities.Core (17.2)
|
|
||||||
Microsoft.Build.Framework (>= 17.2)
|
|
||||||
Microsoft.NET.StringTools (>= 1.0)
|
|
||||||
Microsoft.Win32.Registry (>= 4.3)
|
|
||||||
System.Collections.Immutable (>= 5.0)
|
|
||||||
System.Configuration.ConfigurationManager (>= 4.7)
|
|
||||||
System.Security.Permissions (>= 4.7) - restriction: == netstandard2.0
|
|
||||||
System.Text.Encoding.CodePages (>= 4.0.1) - restriction: == netstandard2.0
|
|
||||||
Microsoft.NET.StringTools (1.0)
|
|
||||||
System.Memory (>= 4.5.4)
|
|
||||||
System.Runtime.CompilerServices.Unsafe (>= 5.0)
|
|
||||||
Microsoft.NETCore.Platforms (6.0.5) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard1.2)) (&& (== net6.0) (< netstandard1.3)) (&& (== net6.0) (< netstandard1.5)) (== netstandard2.0)
|
|
||||||
Microsoft.NETCore.Targets (5.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard1.2)) (&& (== net6.0) (< netstandard1.3)) (&& (== net6.0) (< netstandard1.5)) (== netstandard2.0)
|
|
||||||
Microsoft.Win32.Registry (5.0)
|
|
||||||
System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monoandroid) (< netstandard1.3)) (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (== netstandard2.0)
|
|
||||||
System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0)
|
|
||||||
System.Security.AccessControl (>= 5.0)
|
|
||||||
System.Security.Principal.Windows (>= 5.0)
|
|
||||||
Microsoft.Win32.SystemEvents (6.0.1) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1))
|
|
||||||
Mono.Posix.NETStandard (1.0)
|
|
||||||
MSBuild.StructuredLogger (2.1.669)
|
|
||||||
Microsoft.Build (>= 16.10)
|
|
||||||
Microsoft.Build.Framework (>= 16.10)
|
|
||||||
Microsoft.Build.Tasks.Core (>= 16.10)
|
|
||||||
Microsoft.Build.Utilities.Core (>= 16.10)
|
|
||||||
Newtonsoft.Json (13.0.1)
|
|
||||||
NuGet.Common (6.3)
|
|
||||||
NuGet.Frameworks (>= 6.3)
|
|
||||||
NuGet.Configuration (6.3)
|
|
||||||
NuGet.Common (>= 6.3)
|
|
||||||
System.Security.Cryptography.ProtectedData (>= 4.4)
|
|
||||||
NuGet.Frameworks (6.3)
|
|
||||||
NuGet.Packaging (6.3)
|
|
||||||
Newtonsoft.Json (>= 13.0.1)
|
|
||||||
NuGet.Configuration (>= 6.3)
|
|
||||||
NuGet.Versioning (>= 6.3)
|
|
||||||
System.Security.Cryptography.Cng (>= 5.0)
|
|
||||||
System.Security.Cryptography.Pkcs (>= 5.0)
|
|
||||||
NuGet.Protocol (6.3)
|
|
||||||
NuGet.Packaging (>= 6.3)
|
|
||||||
NuGet.Versioning (6.3)
|
|
||||||
System.Buffers (4.5.1) - restriction: || (&& (== net6.0) (>= monoandroid) (< netstandard1.3)) (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (== netstandard2.0)
|
|
||||||
System.CodeDom (6.0)
|
|
||||||
System.Collections.Immutable (6.0)
|
|
||||||
System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0)
|
|
||||||
System.Runtime.CompilerServices.Unsafe (>= 6.0)
|
|
||||||
System.Configuration.ConfigurationManager (6.0)
|
|
||||||
System.Security.Cryptography.ProtectedData (>= 6.0)
|
|
||||||
System.Security.Permissions (>= 6.0)
|
|
||||||
System.Drawing.Common (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1))
|
|
||||||
Microsoft.Win32.SystemEvents (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1))
|
|
||||||
System.Formats.Asn1 (6.0)
|
|
||||||
System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0)
|
|
||||||
System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0)
|
|
||||||
System.Memory (4.5.5)
|
|
||||||
System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (== netstandard2.0)
|
|
||||||
System.Numerics.Vectors (>= 4.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (== netstandard2.0)
|
|
||||||
System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (== netstandard2.0)
|
|
||||||
System.Numerics.Vectors (4.5) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0)
|
|
||||||
System.Reactive (5.0)
|
|
||||||
System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0)
|
|
||||||
System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net472)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0)
|
|
||||||
System.Reflection.Metadata (6.0.1)
|
|
||||||
System.Collections.Immutable (>= 6.0)
|
|
||||||
System.Resources.Extensions (6.0)
|
|
||||||
System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0)
|
|
||||||
System.Runtime (4.3.1) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0)
|
|
||||||
Microsoft.NETCore.Platforms (>= 1.1.1)
|
|
||||||
Microsoft.NETCore.Targets (>= 1.1.3)
|
|
||||||
System.Runtime.CompilerServices.Unsafe (6.0)
|
|
||||||
System.Runtime.InteropServices.WindowsRuntime (4.3) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0)
|
|
||||||
System.Runtime (>= 4.3)
|
|
||||||
System.Security.AccessControl (6.0)
|
|
||||||
System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0)
|
|
||||||
System.Security.Cryptography.Cng (5.0)
|
|
||||||
System.Formats.Asn1 (>= 5.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.0))
|
|
||||||
System.Security.Cryptography.Pkcs (6.0.1)
|
|
||||||
System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0)
|
|
||||||
System.Formats.Asn1 (>= 6.0)
|
|
||||||
System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0)
|
|
||||||
System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0)
|
|
||||||
System.Security.Cryptography.ProtectedData (6.0)
|
|
||||||
System.Security.Cryptography.Xml (6.0.1)
|
|
||||||
System.Memory (>= 4.5.4) - restriction: == netstandard2.0
|
|
||||||
System.Security.AccessControl (>= 6.0)
|
|
||||||
System.Security.Cryptography.Pkcs (>= 6.0.1)
|
|
||||||
System.Security.Permissions (6.0)
|
|
||||||
System.Security.AccessControl (>= 6.0)
|
|
||||||
System.Windows.Extensions (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1))
|
|
||||||
System.Security.Principal.Windows (5.0)
|
|
||||||
System.Text.Encoding.CodePages (6.0)
|
|
||||||
System.Runtime.CompilerServices.Unsafe (>= 6.0)
|
|
||||||
System.Text.Encodings.Web (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Runtime.CompilerServices.Unsafe (>= 6.0)
|
|
||||||
System.Text.Json (6.0.5) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0))
|
|
||||||
System.Runtime.CompilerServices.Unsafe (>= 6.0)
|
|
||||||
System.Text.Encodings.Web (>= 6.0)
|
|
||||||
System.Threading.Tasks.Dataflow (6.0)
|
|
||||||
System.Threading.Tasks.Extensions (4.5.4) - restriction: || (&& (== net6.0) (>= net472)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0)
|
|
||||||
System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= wp8)) (== netstandard2.0)
|
|
||||||
System.Windows.Extensions (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1))
|
|
||||||
System.Drawing.Common (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1))
|
|
||||||
7
fake.sh
7
fake.sh
@@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
dotnet tool restore
|
|
||||||
dotnet fake "$@"
|
|
||||||
@@ -27,8 +27,6 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Profiles", "JobsJobsJobs\Pr
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SuccessStories", "JobsJobsJobs\SuccessStories\JobsJobsJobs.SuccessStories.fsproj", "{8DAFA6F6-0415-4507-B31C-7FEBE0D2E9D7}"
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SuccessStories", "JobsJobsJobs\SuccessStories\JobsJobsJobs.SuccessStories.fsproj", "{8DAFA6F6-0415-4507-B31C-7FEBE0D2E9D7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "JobsJobsJobs.V3Migration", "JobsJobsJobs\JobsJobsJobs.V3Migration\JobsJobsJobs.V3Migration.fsproj", "{DC3E225D-9720-44E8-86AE-DEE71262C9F0}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -39,10 +37,6 @@ Global
|
|||||||
{8F5A3D1E-562B-4F27-9787-6CB14B35E69E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{8F5A3D1E-562B-4F27-9787-6CB14B35E69E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{8F5A3D1E-562B-4F27-9787-6CB14B35E69E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{8F5A3D1E-562B-4F27-9787-6CB14B35E69E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{8F5A3D1E-562B-4F27-9787-6CB14B35E69E}.Release|Any CPU.Build.0 = Release|Any CPU
|
{8F5A3D1E-562B-4F27-9787-6CB14B35E69E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{DC3E225D-9720-44E8-86AE-DEE71262C9F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{DC3E225D-9720-44E8-86AE-DEE71262C9F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{DC3E225D-9720-44E8-86AE-DEE71262C9F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{DC3E225D-9720-44E8-86AE-DEE71262C9F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D6E4A943-5113-41ED-A547-8D3BE5516DC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{D6E4A943-5113-41ED-A547-8D3BE5516DC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{D6E4A943-5113-41ED-A547-8D3BE5516DC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D6E4A943-5113-41ED-A547-8D3BE5516DC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D6E4A943-5113-41ED-A547-8D3BE5516DC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D6E4A943-5113-41ED-A547-8D3BE5516DC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@@ -76,7 +70,6 @@ Global
|
|||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{8F5A3D1E-562B-4F27-9787-6CB14B35E69E} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
{8F5A3D1E-562B-4F27-9787-6CB14B35E69E} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
||||||
{DC3E225D-9720-44E8-86AE-DEE71262C9F0} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
|
||||||
{D6E4A943-5113-41ED-A547-8D3BE5516DC0} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
{D6E4A943-5113-41ED-A547-8D3BE5516DC0} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
||||||
{4C184AB8-DDA7-4545-BC84-A4ACCBE29764} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
{4C184AB8-DDA7-4545-BC84-A4ACCBE29764} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
||||||
{0B89D606-A094-4E82-8F8A-9D72D6A0E805} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
{0B89D606-A094-4E82-8F8A-9D72D6A0E805} = {FA833B24-B8F6-4CE6-A044-99257EAC02FF}
|
||||||
|
|||||||
@@ -13,13 +13,14 @@ let private locker = obj ()
|
|||||||
|
|
||||||
/// Delete a citizen by their ID using the given connection properties
|
/// Delete a citizen by their ID using the given connection properties
|
||||||
let private doDeleteById citizenId connProps = backgroundTask {
|
let private doDeleteById citizenId connProps = backgroundTask {
|
||||||
|
let citId = CitizenId.toString citizenId
|
||||||
let! _ =
|
let! _ =
|
||||||
connProps
|
connProps
|
||||||
|> Sql.query $"
|
|> Sql.query $"
|
||||||
DELETE FROM {Table.Success} WHERE data ->> 'citizenId' = @id;
|
DELETE FROM {Table.Success} WHERE data @> @criteria;
|
||||||
DELETE FROM {Table.Listing} WHERE data ->> 'citizenId' = @id;
|
DELETE FROM {Table.Listing} WHERE data @> @criteria;
|
||||||
DELETE FROM {Table.Citizen} WHERE id = @id"
|
DELETE FROM {Table.Citizen} WHERE id = @id"
|
||||||
|> Sql.parameters [ "@id", Sql.string (CitizenId.toString citizenId) ]
|
|> Sql.parameters [ "@criteria", Sql.jsonb (mkDoc {| citizenId = citId |}); "@id", Sql.string citId ]
|
||||||
|> Sql.executeNonQueryAsync
|
|> Sql.executeNonQueryAsync
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
@@ -89,15 +90,11 @@ let register citizen (security : SecurityInfo) = backgroundTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to find the security information matching a confirmation token
|
/// Try to find the security information matching a confirmation token
|
||||||
let private tryConfirmToken token connProps = backgroundTask {
|
let private tryConfirmToken (token : string) connProps = backgroundTask {
|
||||||
let! tryInfo =
|
let! tryInfo =
|
||||||
connProps
|
connProps
|
||||||
|> Sql.query $"
|
|> Sql.query $" SELECT * FROM {Table.SecurityInfo} WHERE data @> @criteria"
|
||||||
SELECT *
|
|> Sql.parameters [ "criteria", Sql.jsonb (mkDoc {| token = token; tokenUsage = "confirm" |}) ]
|
||||||
FROM {Table.SecurityInfo}
|
|
||||||
WHERE data ->> 'token' = @token
|
|
||||||
AND data ->> 'tokenUsage' = 'confirm'"
|
|
||||||
|> Sql.parameters [ "@token", Sql.string token ]
|
|
||||||
|> Sql.executeAsync toDocument<SecurityInfo>
|
|> Sql.executeAsync toDocument<SecurityInfo>
|
||||||
return List.tryHead tryInfo
|
return List.tryHead tryInfo
|
||||||
}
|
}
|
||||||
@@ -132,12 +129,8 @@ let tryLogOn email password (pwVerify : Citizen -> string -> bool option) (pwHas
|
|||||||
let connProps = dataSource ()
|
let connProps = dataSource ()
|
||||||
let! tryCitizen =
|
let! tryCitizen =
|
||||||
connProps
|
connProps
|
||||||
|> Sql.query $"
|
|> Sql.query $"SELECT * FROM {Table.Citizen} WHERE data @> @criteria"
|
||||||
SELECT *
|
|> Sql.parameters [ "@criteria", Sql.jsonb (mkDoc {| email = email; isLegacy = false |}) ]
|
||||||
FROM {Table.Citizen}
|
|
||||||
WHERE data ->> 'email' = @email
|
|
||||||
AND data ->> 'isLegacy' = 'false'"
|
|
||||||
|> Sql.parameters [ "@email", Sql.string email ]
|
|
||||||
|> Sql.executeAsync toDocument<Citizen>
|
|> Sql.executeAsync toDocument<Citizen>
|
||||||
match List.tryHead tryCitizen with
|
match List.tryHead tryCitizen with
|
||||||
| Some citizen ->
|
| Some citizen ->
|
||||||
@@ -176,8 +169,8 @@ let tryByEmailWithSecurity email = backgroundTask {
|
|||||||
SELECT c.*, s.data AS sec_data
|
SELECT c.*, s.data AS sec_data
|
||||||
FROM {Table.Citizen} c
|
FROM {Table.Citizen} c
|
||||||
INNER JOIN {Table.SecurityInfo} s ON s.id = c.id
|
INNER JOIN {Table.SecurityInfo} s ON s.id = c.id
|
||||||
WHERE c.data ->> 'email' = @email"
|
WHERE c.data @> @criteria"
|
||||||
|> Sql.parameters [ "@email", Sql.string email ]
|
|> Sql.parameters [ "@criteria", Sql.jsonb (mkDoc {| email = email |}) ]
|
||||||
|> Sql.executeAsync toCitizenSecurityPair
|
|> Sql.executeAsync toCitizenSecurityPair
|
||||||
return List.tryHead results
|
return List.tryHead results
|
||||||
}
|
}
|
||||||
@@ -188,12 +181,12 @@ let saveSecurityInfo security = backgroundTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to retrieve security information by the given token
|
/// Try to retrieve security information by the given token
|
||||||
let trySecurityByToken token = backgroundTask {
|
let trySecurityByToken (token : string) = backgroundTask {
|
||||||
do! checkForPurge false
|
do! checkForPurge false
|
||||||
let! results =
|
let! results =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"SELECT * FROM {Table.SecurityInfo} WHERE data ->> 'token' = @token"
|
|> Sql.query $"SELECT * FROM {Table.SecurityInfo} WHERE data @> @criteria"
|
||||||
|> Sql.parameters [ "@token", Sql.string token ]
|
|> Sql.parameters [ "@criteria", Sql.jsonb (mkDoc {| token = token |}) ]
|
||||||
|> Sql.executeAsync toDocument<SecurityInfo>
|
|> Sql.executeAsync toDocument<SecurityInfo>
|
||||||
return List.tryHead results
|
return List.tryHead results
|
||||||
}
|
}
|
||||||
@@ -204,7 +197,11 @@ let trySecurityByToken token = backgroundTask {
|
|||||||
let legacy () = backgroundTask {
|
let legacy () = backgroundTask {
|
||||||
return!
|
return!
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"SELECT * FROM {Table.Citizen} WHERE data ->> 'isLegacy' = 'true' ORDER BY data ->> 'firstName'"
|
|> Sql.query $"""
|
||||||
|
SELECT *
|
||||||
|
FROM {Table.Citizen}
|
||||||
|
WHERE data @> '{{ "isLegacy": true }}'::jsonb
|
||||||
|
ORDER BY data ->> 'firstName'"""
|
||||||
|> Sql.executeAsync toDocument<Citizen>
|
|> Sql.executeAsync toDocument<Citizen>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,13 +209,13 @@ let legacy () = backgroundTask {
|
|||||||
let current () = backgroundTask {
|
let current () = backgroundTask {
|
||||||
return!
|
return!
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"
|
|> Sql.query $"""
|
||||||
SELECT c.*
|
SELECT c.*
|
||||||
FROM {Table.Citizen} c
|
FROM {Table.Citizen} c
|
||||||
INNER JOIN {Table.SecurityInfo} si ON si.id = c.id
|
INNER JOIN {Table.SecurityInfo} si ON si.id = c.id
|
||||||
WHERE c.data ->> 'isLegacy' = 'false'
|
WHERE c.data @> '{{ "isLegacy": false }}'::jsonb
|
||||||
AND si.data ->> 'accountLocked' = 'false'
|
AND si.data @> '{{ "accountLocked": false }}'::jsonb
|
||||||
AND NOT EXISTS (SELECT 1 FROM {Table.Profile} p WHERE p.id = c.id)"
|
AND NOT EXISTS (SELECT 1 FROM {Table.Profile} p WHERE p.id = c.id)"""
|
||||||
|> Sql.executeAsync toDocument<Citizen>
|
|> Sql.executeAsync toDocument<Citizen>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,11 +238,12 @@ let migrateLegacy currentId legacyId = backgroundTask {
|
|||||||
Table.Profile (CitizenId.toString currentId) (Sql.existingConnection conn)
|
Table.Profile (CitizenId.toString currentId) (Sql.existingConnection conn)
|
||||||
(mkDoc { profile with Id = currentId; IsLegacy = false })
|
(mkDoc { profile with Id = currentId; IsLegacy = false })
|
||||||
| None -> ()
|
| None -> ()
|
||||||
|
let oldCriteria = mkDoc {| citizenId = oldId |}
|
||||||
let! listings =
|
let! listings =
|
||||||
conn
|
conn
|
||||||
|> Sql.existingConnection
|
|> Sql.existingConnection
|
||||||
|> Sql.query $"SELECT * FROM {Table.Listing} WHERE data ->> 'citizenId' = @oldId"
|
|> Sql.query $"SELECT * FROM {Table.Listing} WHERE data @> @criteria"
|
||||||
|> Sql.parameters [ "@oldId", Sql.string oldId ]
|
|> Sql.parameters [ "@criteria", Sql.jsonb oldCriteria ]
|
||||||
|> Sql.executeAsync toDocument<Listing>
|
|> Sql.executeAsync toDocument<Listing>
|
||||||
for listing in listings do
|
for listing in listings do
|
||||||
let newListing = { listing with Id = ListingId.create (); CitizenId = currentId; IsLegacy = false }
|
let newListing = { listing with Id = ListingId.create (); CitizenId = currentId; IsLegacy = false }
|
||||||
@@ -254,8 +252,8 @@ let migrateLegacy currentId legacyId = backgroundTask {
|
|||||||
let! successes =
|
let! successes =
|
||||||
conn
|
conn
|
||||||
|> Sql.existingConnection
|
|> Sql.existingConnection
|
||||||
|> Sql.query $"SELECT * FROM {Table.Success} WHERE data ->> 'citizenId' = @oldId"
|
|> Sql.query $"SELECT * FROM {Table.Success} WHERE data @> @criteria"
|
||||||
|> Sql.parameters [ "@oldId", Sql.string oldId ]
|
|> Sql.parameters [ "@criteria", Sql.jsonb oldCriteria ]
|
||||||
|> Sql.executeAsync toDocument<Success>
|
|> Sql.executeAsync toDocument<Success>
|
||||||
for success in successes do
|
for success in successes do
|
||||||
let newSuccess = { success with Id = SuccessId.create (); CitizenId = currentId }
|
let newSuccess = { success with Id = SuccessId.create (); CitizenId = currentId }
|
||||||
@@ -266,10 +264,10 @@ let migrateLegacy currentId legacyId = backgroundTask {
|
|||||||
conn
|
conn
|
||||||
|> Sql.existingConnection
|
|> Sql.existingConnection
|
||||||
|> Sql.query $"
|
|> Sql.query $"
|
||||||
DELETE FROM {Table.Success} WHERE data ->> 'citizenId' = @oldId;
|
DELETE FROM {Table.Success} WHERE data @> @criteria;
|
||||||
DELETE FROM {Table.Listing} WHERE data ->> 'citizenId' = @oldId;
|
DELETE FROM {Table.Listing} WHERE data @> @criteria;
|
||||||
DELETE FROM {Table.Citizen} WHERE id = @oldId"
|
DELETE FROM {Table.Citizen} WHERE id = @oldId"
|
||||||
|> Sql.parameters [ "@oldId", Sql.string oldId ]
|
|> Sql.parameters [ "@criteria", Sql.jsonb oldCriteria; "@oldId", Sql.string oldId ]
|
||||||
|> Sql.executeNonQueryAsync
|
|> Sql.executeNonQueryAsync
|
||||||
do! txn.CommitAsync ()
|
do! txn.CommitAsync ()
|
||||||
return Ok ""
|
return Ok ""
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ let dashboard (citizen : Citizen) (profile : Profile option) profileCount tz =
|
|||||||
emptyP
|
emptyP
|
||||||
p [] [
|
p [] [
|
||||||
txt "To see how this application works, check out “How It Works” in the sidebar (last updated "
|
txt "To see how this application works, check out “How It Works” in the sidebar (last updated "
|
||||||
txt "August 29<sup>th</sup>, 2021)."
|
txt "February 2<sup>nd</sup>, 2023)."
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -74,20 +74,20 @@ type DistributedCache () =
|
|||||||
dataSource
|
dataSource
|
||||||
|> Sql.query $"
|
|> Sql.query $"
|
||||||
SELECT EXISTS
|
SELECT EXISTS
|
||||||
(SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'session')
|
(SELECT 1 FROM pg_tables WHERE schemaname = 'jjj' AND tablename = 'session')
|
||||||
AS does_exist"
|
AS does_exist"
|
||||||
|> Sql.executeRowAsync (fun row -> row.bool "does_exist")
|
|> Sql.executeRowAsync (fun row -> row.bool "does_exist")
|
||||||
if not exists then
|
if not exists then
|
||||||
let! _ =
|
let! _ =
|
||||||
dataSource
|
dataSource
|
||||||
|> Sql.query
|
|> Sql.query
|
||||||
"CREATE TABLE session (
|
"CREATE TABLE jjj.session (
|
||||||
id TEXT NOT NULL PRIMARY KEY,
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
payload BYTEA NOT NULL,
|
payload BYTEA NOT NULL,
|
||||||
expire_at TIMESTAMPTZ NOT NULL,
|
expire_at TIMESTAMPTZ NOT NULL,
|
||||||
sliding_expiration INTERVAL,
|
sliding_expiration INTERVAL,
|
||||||
absolute_expiration TIMESTAMPTZ);
|
absolute_expiration TIMESTAMPTZ);
|
||||||
CREATE INDEX idx_session_expiration ON session (expire_at)"
|
CREATE INDEX idx_session_expiration ON jjj.session (expire_at)"
|
||||||
|> Sql.executeNonQueryAsync
|
|> Sql.executeNonQueryAsync
|
||||||
()
|
()
|
||||||
} |> sync
|
} |> sync
|
||||||
@@ -100,7 +100,7 @@ type DistributedCache () =
|
|||||||
let idParam = "@id", Sql.string key
|
let idParam = "@id", Sql.string key
|
||||||
let! tryEntry =
|
let! tryEntry =
|
||||||
dataSource
|
dataSource
|
||||||
|> Sql.query "SELECT * FROM session WHERE id = @id"
|
|> Sql.query "SELECT * FROM jjj.session WHERE id = @id"
|
||||||
|> Sql.parameters [ idParam ]
|
|> Sql.parameters [ idParam ]
|
||||||
|> Sql.executeAsync (fun row ->
|
|> Sql.executeAsync (fun row ->
|
||||||
{ Id = row.string "id"
|
{ Id = row.string "id"
|
||||||
@@ -123,7 +123,7 @@ type DistributedCache () =
|
|||||||
if needsRefresh then
|
if needsRefresh then
|
||||||
let! _ =
|
let! _ =
|
||||||
dataSource
|
dataSource
|
||||||
|> Sql.query "UPDATE session SET expire_at = @expireAt WHERE id = @id"
|
|> Sql.query "UPDATE jjj.session SET expire_at = @expireAt WHERE id = @id"
|
||||||
|> Sql.parameters [ expireParam item.ExpireAt; idParam ]
|
|> Sql.parameters [ expireParam item.ExpireAt; idParam ]
|
||||||
|> Sql.executeNonQueryAsync
|
|> Sql.executeNonQueryAsync
|
||||||
()
|
()
|
||||||
@@ -140,7 +140,7 @@ type DistributedCache () =
|
|||||||
if lastPurge.Plus (Duration.FromMinutes 30L) < now then
|
if lastPurge.Plus (Duration.FromMinutes 30L) < now then
|
||||||
let! _ =
|
let! _ =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query "DELETE FROM session WHERE expire_at < @expireAt"
|
|> Sql.query "DELETE FROM jjj.session WHERE expire_at < @expireAt"
|
||||||
|> Sql.parameters [ expireParam now ]
|
|> Sql.parameters [ expireParam now ]
|
||||||
|> Sql.executeNonQueryAsync
|
|> Sql.executeNonQueryAsync
|
||||||
lastPurge <- now
|
lastPurge <- now
|
||||||
@@ -150,7 +150,7 @@ type DistributedCache () =
|
|||||||
let removeEntry key = backgroundTask {
|
let removeEntry key = backgroundTask {
|
||||||
let! _ =
|
let! _ =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query "DELETE FROM session WHERE id = @id"
|
|> Sql.query "DELETE FROM jjj.session WHERE id = @id"
|
||||||
|> Sql.parameters [ "@id", Sql.string key ]
|
|> Sql.parameters [ "@id", Sql.string key ]
|
||||||
|> Sql.executeNonQueryAsync
|
|> Sql.executeNonQueryAsync
|
||||||
()
|
()
|
||||||
@@ -176,7 +176,7 @@ type DistributedCache () =
|
|||||||
let! _ =
|
let! _ =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query
|
|> Sql.query
|
||||||
"INSERT INTO session (
|
"INSERT INTO jjj.session (
|
||||||
id, payload, expire_at, sliding_expiration, absolute_expiration
|
id, payload, expire_at, sliding_expiration, absolute_expiration
|
||||||
) VALUES (
|
) VALUES (
|
||||||
@id, @payload, @expireAt, @slideExp, @absExp
|
@id, @payload, @expireAt, @slideExp, @absExp
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ module Layout =
|
|||||||
let version =
|
let version =
|
||||||
seq {
|
seq {
|
||||||
string v.Major
|
string v.Major
|
||||||
if v.Minor > 0 then
|
if v.Minor > 0 || v.Build > 0 then
|
||||||
"."; string v.Minor
|
"."; string v.Minor
|
||||||
if v.Build > 0 then
|
if v.Build > 0 then
|
||||||
"."; string v.Build
|
"."; string v.Build
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
<GenerateDocumentationFile>false</GenerateDocumentationFile>
|
<GenerateDocumentationFile>false</GenerateDocumentationFile>
|
||||||
<AssemblyVersion>3.0.0.0</AssemblyVersion>
|
<AssemblyVersion>3.0.2.0</AssemblyVersion>
|
||||||
<FileVersion>3.0.0.0</FileVersion>
|
<FileVersion>3.0.2.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ let privacyPolicy =
|
|||||||
let appName = txt "Jobs, Jobs, Jobs"
|
let appName = txt "Jobs, Jobs, Jobs"
|
||||||
article [] [
|
article [] [
|
||||||
h3 [] [ txt "Privacy Policy" ]
|
h3 [] [ txt "Privacy Policy" ]
|
||||||
p [ _class "fst-italic" ] [ txt "(as of December 27<sup>th</sup>, 2022)" ]
|
p [ _class "fst-italic" ] [ txt "(as of February 2<sup>nd</sup>, 2023)" ]
|
||||||
|
|
||||||
p [] [
|
p [] [
|
||||||
appName; txt " (“we,” “our,” or “us”) is committed to protecting your "
|
appName; txt " (“we,” “our,” or “us”) is committed to protecting your "
|
||||||
@@ -477,7 +477,7 @@ let privacyPolicy =
|
|||||||
|
|
||||||
hr []
|
hr []
|
||||||
|
|
||||||
p [ _class "fst-italic" ] [ txt "Changes for "; appName; txt " v3 (December 27<sup>th</sup>, 2022)" ]
|
p [ _class "fst-italic" ] [ txt "Changes for "; appName; txt " v3 (February 2<sup>nd</sup>, 2023)" ]
|
||||||
ul [] [
|
ul [] [
|
||||||
li [ _class "fst-italic" ] [ txt "Removed references to Mastodon" ]
|
li [ _class "fst-italic" ] [ txt "Removed references to Mastodon" ]
|
||||||
li [ _class "fst-italic" ] [ txt "Added references to job listings" ]
|
li [ _class "fst-italic" ] [ txt "Added references to job listings" ]
|
||||||
@@ -494,7 +494,7 @@ let privacyPolicy =
|
|||||||
let termsOfService =
|
let termsOfService =
|
||||||
article [] [
|
article [] [
|
||||||
h3 [] [ txt "Terms of Service" ]
|
h3 [] [ txt "Terms of Service" ]
|
||||||
p [ _class "fst-italic" ] [ txt "(as of August 30<sup>th</sup>, 2022)" ]
|
p [ _class "fst-italic" ] [ txt "(as of February 2<sup>nd</sup>, 2023)" ]
|
||||||
h4 [] [ txt "Acceptance of Terms" ]
|
h4 [] [ txt "Acceptance of Terms" ]
|
||||||
p [] [
|
p [] [
|
||||||
txt "By accessing this web site, you are agreeing to be bound by these Terms and Conditions, and that you "
|
txt "By accessing this web site, you are agreeing to be bound by these Terms and Conditions, and that you "
|
||||||
@@ -528,7 +528,7 @@ let termsOfService =
|
|||||||
]
|
]
|
||||||
hr []
|
hr []
|
||||||
p [ _class "fst-italic" ] [
|
p [ _class "fst-italic" ] [
|
||||||
txt "Change on August 30<sup>th</sup>, 2022 – added references to job listings, removed references "
|
txt "Change on February 2<sup>nd</sup>, 2023 – added references to job listings, removed references "
|
||||||
txt "to Mastodon instances."
|
txt "to Mastodon instances."
|
||||||
]
|
]
|
||||||
p [ _class "fst-italic" ] [
|
p [ _class "fst-italic" ] [
|
||||||
@@ -945,7 +945,7 @@ module Help =
|
|||||||
let index =
|
let index =
|
||||||
article [] [
|
article [] [
|
||||||
h3 [ _class "mb-0" ] [ txt "How It Works" ]
|
h3 [ _class "mb-0" ] [ txt "How It Works" ]
|
||||||
h6 [ _class "mb-3 text-muted fst-italic" ] [ txt "Last Updated January 22<sup>nd</sup>, 2023" ]
|
h6 [ _class "mb-3 text-muted fst-italic" ] [ txt "Last Updated February 2<sup>nd</sup>, 2023" ]
|
||||||
|
|
||||||
p [ _class "fst-italic" ] [
|
p [ _class "fst-italic" ] [
|
||||||
txt "Show me how to "; a [ _href "/how-it-works/listings#searching" ] [ txt "find a job" ]
|
txt "Show me how to "; a [ _href "/how-it-works/listings#searching" ] [ txt "find a job" ]
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
|
||||||
<SelfContained>false</SelfContained>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Program.fs" />
|
|
||||||
<Content Include="appsettings.Migration.json" CopyToOutputDirectory="Always" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.0.0" />
|
|
||||||
<PackageReference Include="RethinkDb.Driver.FSharp" Version="0.9.0-beta-07" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Application\JobsJobsJobs.Application.fsproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
|
|
||||||
open System.Text.Json
|
|
||||||
open Microsoft.Extensions.Configuration
|
|
||||||
|
|
||||||
/// Data access for v2 Jobs, Jobs, Jobs
|
|
||||||
module Rethink =
|
|
||||||
|
|
||||||
/// Table names
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module Table =
|
|
||||||
/// The user (citizen of Gitmo Nation) table
|
|
||||||
let Citizen = "citizen"
|
|
||||||
/// The continent table
|
|
||||||
let Continent = "continent"
|
|
||||||
/// The job listing table
|
|
||||||
let Listing = "listing"
|
|
||||||
/// The citizen employment profile table
|
|
||||||
let Profile = "profile"
|
|
||||||
/// The success story table
|
|
||||||
let Success = "success"
|
|
||||||
/// All tables
|
|
||||||
let all () = [ Citizen; Continent; Listing; Profile; Success ]
|
|
||||||
|
|
||||||
open RethinkDb.Driver.Net
|
|
||||||
|
|
||||||
/// Functions run at startup
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module Startup =
|
|
||||||
|
|
||||||
open NodaTime
|
|
||||||
open NodaTime.Serialization.JsonNet
|
|
||||||
open RethinkDb.Driver.FSharp
|
|
||||||
|
|
||||||
/// Create a RethinkDB connection
|
|
||||||
let createConnection (connStr : string) =
|
|
||||||
// Add all required JSON converters
|
|
||||||
Converter.Serializer.ConfigureForNodaTime DateTimeZoneProviders.Tzdb |> ignore
|
|
||||||
// Connect to the database
|
|
||||||
let config = DataConfig.FromUri connStr
|
|
||||||
config.CreateConnection ()
|
|
||||||
|
|
||||||
/// Shorthand for the RethinkDB R variable (how every command starts)
|
|
||||||
let r = RethinkDb.Driver.RethinkDB.R
|
|
||||||
|
|
||||||
open JobsJobsJobs
|
|
||||||
open JobsJobsJobs.Common.Data
|
|
||||||
open JobsJobsJobs.Domain
|
|
||||||
open Newtonsoft.Json.Linq
|
|
||||||
open NodaTime.Text
|
|
||||||
open Npgsql.FSharp
|
|
||||||
open RethinkDb.Driver.FSharp.Functions
|
|
||||||
|
|
||||||
/// Retrieve an instant from a JObject field
|
|
||||||
let getInstant (doc : JObject) name =
|
|
||||||
let text = doc[name].Value<string> ()
|
|
||||||
match InstantPattern.General.Parse text with
|
|
||||||
| it when it.Success -> it.Value
|
|
||||||
| _ ->
|
|
||||||
match InstantPattern.ExtendedIso.Parse text with
|
|
||||||
| it when it.Success -> it.Value
|
|
||||||
| it -> raise it.Exception
|
|
||||||
|
|
||||||
task {
|
|
||||||
// Establish database connections
|
|
||||||
let cfg = ConfigurationBuilder().AddJsonFile("appsettings.Migration.json").Build ()
|
|
||||||
use rethinkConn = Rethink.Startup.createConnection (cfg.GetConnectionString "RethinkDB")
|
|
||||||
do! setUp cfg
|
|
||||||
let pgConn = dataSource ()
|
|
||||||
|
|
||||||
let getOld table =
|
|
||||||
fromTable table
|
|
||||||
|> runResult<JObject list>
|
|
||||||
|> withRetryOnce
|
|
||||||
|> withConn rethinkConn
|
|
||||||
|
|
||||||
// Migrate citizens
|
|
||||||
let! oldCitizens = getOld Rethink.Table.Citizen
|
|
||||||
let newCitizens =
|
|
||||||
oldCitizens
|
|
||||||
|> List.map (fun c ->
|
|
||||||
let user = c["mastodonUser"].Value<string> ()
|
|
||||||
{ Citizen.empty with
|
|
||||||
Id = CitizenId.ofString (c["id"].Value<string> ())
|
|
||||||
JoinedOn = getInstant c "joinedOn"
|
|
||||||
LastSeenOn = getInstant c "lastSeenOn"
|
|
||||||
Email = $"""{user}@{c["instance"].Value<string> ()}"""
|
|
||||||
FirstName = user
|
|
||||||
LastName = user
|
|
||||||
IsLegacy = true
|
|
||||||
})
|
|
||||||
for citizen in newCitizens do
|
|
||||||
do! Citizens.Data.save citizen
|
|
||||||
let! _ =
|
|
||||||
pgConn
|
|
||||||
|> Sql.executeTransactionAsync [
|
|
||||||
$"INSERT INTO {Table.SecurityInfo} VALUES (@id, @data)",
|
|
||||||
newCitizens |> List.map (fun c ->
|
|
||||||
let info = { SecurityInfo.empty with Id = c.Id; AccountLocked = true }
|
|
||||||
[ "@id", Sql.string (CitizenId.toString c.Id)
|
|
||||||
"@data", Sql.jsonb (JsonSerializer.Serialize (info, Json.options))
|
|
||||||
])
|
|
||||||
]
|
|
||||||
printfn $"** Migrated {List.length newCitizens} citizens"
|
|
||||||
|
|
||||||
// Migrate continents
|
|
||||||
let! oldContinents = getOld Rethink.Table.Continent
|
|
||||||
let newContinents =
|
|
||||||
oldContinents
|
|
||||||
|> List.map (fun c ->
|
|
||||||
{ Continent.empty with
|
|
||||||
Id = ContinentId.ofString (c["id"].Value<string> ())
|
|
||||||
Name = c["name"].Value<string> ()
|
|
||||||
})
|
|
||||||
let! _ =
|
|
||||||
pgConn
|
|
||||||
|> Sql.executeTransactionAsync [
|
|
||||||
$"INSERT INTO {Table.Continent} VALUES (@id, @data)",
|
|
||||||
newContinents |> List.map (fun c -> [
|
|
||||||
"@id", Sql.string (ContinentId.toString c.Id)
|
|
||||||
"@data", Sql.jsonb (JsonSerializer.Serialize (c, Json.options))
|
|
||||||
])
|
|
||||||
]
|
|
||||||
printfn $"** Migrated {List.length newContinents} continents"
|
|
||||||
|
|
||||||
// Migrate profiles
|
|
||||||
let! oldProfiles = getOld Rethink.Table.Profile
|
|
||||||
let newProfiles =
|
|
||||||
oldProfiles
|
|
||||||
|> List.map (fun p ->
|
|
||||||
let experience = p["experience"].Value<string> ()
|
|
||||||
{ Profile.empty with
|
|
||||||
Id = CitizenId.ofString (p["id"].Value<string> ())
|
|
||||||
ContinentId = ContinentId.ofString (p["continentId"].Value<string> ())
|
|
||||||
Region = p["region"].Value<string> ()
|
|
||||||
IsSeekingEmployment = p["seekingEmployment"].Value<bool> ()
|
|
||||||
IsRemote = p["remoteWork"].Value<bool> ()
|
|
||||||
IsFullTime = p["fullTime"].Value<bool> ()
|
|
||||||
Biography = Text (p["biography"].Value<string> ())
|
|
||||||
Experience = if isNull experience then None else Some (Text experience)
|
|
||||||
Skills = p["skills"].Children()
|
|
||||||
|> Seq.map (fun s ->
|
|
||||||
let notes = s["notes"].Value<string> ()
|
|
||||||
{ Description = s["description"].Value<string> ()
|
|
||||||
Notes = if isNull notes then None else Some notes
|
|
||||||
})
|
|
||||||
|> List.ofSeq
|
|
||||||
Visibility = if p["isPublic"].Value<bool> () then Anonymous else Private
|
|
||||||
LastUpdatedOn = getInstant p "lastUpdatedOn"
|
|
||||||
IsLegacy = true
|
|
||||||
})
|
|
||||||
for profile in newProfiles do
|
|
||||||
do! Profiles.Data.save profile
|
|
||||||
printfn $"** Migrated {List.length newProfiles} profiles"
|
|
||||||
|
|
||||||
// Migrate listings
|
|
||||||
let! oldListings = getOld Rethink.Table.Listing
|
|
||||||
let newListings =
|
|
||||||
oldListings
|
|
||||||
|> List.map (fun l ->
|
|
||||||
let neededBy = l["neededBy"].Value<string> ()
|
|
||||||
let wasFilledHere = l["wasFilledHere"].Value<string> ()
|
|
||||||
{ Listing.empty with
|
|
||||||
Id = ListingId.ofString (l["id"].Value<string> ())
|
|
||||||
CitizenId = CitizenId.ofString (l["citizenId"].Value<string> ())
|
|
||||||
CreatedOn = getInstant l "createdOn"
|
|
||||||
Title = l["title"].Value<string> ()
|
|
||||||
ContinentId = ContinentId.ofString (l["continentId"].Value<string> ())
|
|
||||||
Region = l["region"].Value<string> ()
|
|
||||||
IsRemote = l["remoteWork"].Value<bool> ()
|
|
||||||
IsExpired = l["isExpired"].Value<bool> ()
|
|
||||||
UpdatedOn = getInstant l "updatedOn"
|
|
||||||
Text = Text (l["text"].Value<string> ())
|
|
||||||
NeededBy = if isNull neededBy then None else
|
|
||||||
match LocalDatePattern.Iso.Parse neededBy with
|
|
||||||
| it when it.Success -> Some it.Value
|
|
||||||
| it ->
|
|
||||||
eprintfn $"Error parsing date - {it.Exception.Message}"
|
|
||||||
None
|
|
||||||
WasFilledHere = if isNull wasFilledHere then None else Some (bool.Parse wasFilledHere)
|
|
||||||
IsLegacy = true
|
|
||||||
})
|
|
||||||
for listing in newListings do
|
|
||||||
do! Listings.Data.save listing
|
|
||||||
printfn $"** Migrated {List.length newListings} listings"
|
|
||||||
|
|
||||||
// Migrate success stories
|
|
||||||
let! oldSuccesses = getOld Rethink.Table.Success
|
|
||||||
let newSuccesses =
|
|
||||||
oldSuccesses
|
|
||||||
|> List.map (fun s ->
|
|
||||||
let story = s["story"].Value<string> ()
|
|
||||||
{ Success.empty with
|
|
||||||
Id = SuccessId.ofString (s["id"].Value<string> ())
|
|
||||||
CitizenId = CitizenId.ofString (s["citizenId"].Value<string> ())
|
|
||||||
RecordedOn = getInstant s "recordedOn"
|
|
||||||
Source = s["source"].Value<string> ()
|
|
||||||
Story = if isNull story then None else Some (Text story)
|
|
||||||
})
|
|
||||||
for success in newSuccesses do
|
|
||||||
do! SuccessStories.Data.save success
|
|
||||||
printfn $"** Migrated {List.length newSuccesses} successes"
|
|
||||||
|
|
||||||
// Delete any citizens who have no profile, no listing, and no success story recorded
|
|
||||||
let! deleted =
|
|
||||||
pgConn
|
|
||||||
|> Sql.query $"
|
|
||||||
DELETE FROM {Table.Citizen}
|
|
||||||
WHERE id NOT IN (SELECT id FROM {Table.Profile})
|
|
||||||
AND id NOT IN (SELECT DISTINCT data ->> 'citizenId' FROM {Table.Listing})
|
|
||||||
AND id NOT IN (SELECT DISTINCT data ->> 'citizenId' FROM {Table.Success})"
|
|
||||||
|> Sql.executeNonQueryAsync
|
|
||||||
printfn $"** Deleted {deleted} citizens who had no profile, listings, or success stories"
|
|
||||||
|
|
||||||
printfn ""
|
|
||||||
printfn "Migration complete"
|
|
||||||
} |> Async.AwaitTask |> Async.RunSynchronously
|
|
||||||
|
|
||||||
@@ -22,8 +22,9 @@ let private toListingForView row =
|
|||||||
/// Find all job listings posted by the given citizen
|
/// Find all job listings posted by the given citizen
|
||||||
let findByCitizen citizenId =
|
let findByCitizen citizenId =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"{viewSql} WHERE l.data ->> 'citizenId' = @citizenId AND l.data ->> 'isLegacy' = 'false'"
|
|> Sql.query $"{viewSql} WHERE l.data @> @criteria"
|
||||||
|> Sql.parameters [ "@citizenId", Sql.string (CitizenId.toString citizenId) ]
|
|> Sql.parameters
|
||||||
|
[ "@criteria", Sql.jsonb (mkDoc {| citizenId = CitizenId.toString citizenId; isLegacy = false |}) ]
|
||||||
|> Sql.executeAsync toListingForView
|
|> Sql.executeAsync toListingForView
|
||||||
|
|
||||||
/// Find a listing by its ID
|
/// Find a listing by its ID
|
||||||
@@ -38,7 +39,7 @@ let findById listingId = backgroundTask {
|
|||||||
let findByIdForView listingId = backgroundTask {
|
let findByIdForView listingId = backgroundTask {
|
||||||
let! tryListing =
|
let! tryListing =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"{viewSql} WHERE l.id = @id AND l.data ->> 'isLegacy' = 'false'"
|
|> Sql.query $"""{viewSql} WHERE l.id = @id AND l.data @> '{{ "isLegacy": false }}'::jsonb"""
|
||||||
|> Sql.parameters [ "@id", Sql.string (ListingId.toString listingId) ]
|
|> Sql.parameters [ "@id", Sql.string (ListingId.toString listingId) ]
|
||||||
|> Sql.executeAsync toListingForView
|
|> Sql.executeAsync toListingForView
|
||||||
return List.tryHead tryListing
|
return List.tryHead tryListing
|
||||||
@@ -52,18 +53,18 @@ let save (listing : Listing) =
|
|||||||
let search (search : ListingSearchForm) =
|
let search (search : ListingSearchForm) =
|
||||||
let searches = [
|
let searches = [
|
||||||
if search.ContinentId <> "" then
|
if search.ContinentId <> "" then
|
||||||
"l.data ->> 'continentId' = @continentId", [ "@continentId", Sql.string search.ContinentId ]
|
"l.data @> @continent", [ "@continent", Sql.jsonb (mkDoc {| continentId = search.ContinentId |}) ]
|
||||||
if search.Region <> "" then
|
if search.Region <> "" then
|
||||||
"l.data ->> 'region' ILIKE @region", [ "@region", like search.Region ]
|
"l.data ->> 'region' ILIKE @region", [ "@region", like search.Region ]
|
||||||
if search.RemoteWork <> "" then
|
if search.RemoteWork <> "" then
|
||||||
"l.data ->> 'isRemote' = @remote", [ "@remote", jsonBool (search.RemoteWork = "yes") ]
|
"l.data @> @remote", [ "@remote", Sql.jsonb (mkDoc {| isRemote = search.RemoteWork = "yes" |}) ]
|
||||||
if search.Text <> "" then
|
if search.Text <> "" then
|
||||||
"l.data ->> 'text' ILIKE @text", [ "@text", like search.Text ]
|
"l.data ->> 'text' ILIKE @text", [ "@text", like search.Text ]
|
||||||
]
|
]
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"
|
|> Sql.query $"""
|
||||||
{viewSql}
|
{viewSql}
|
||||||
WHERE l.data ->> 'isExpired' = 'false' AND l.data ->> 'isLegacy' = 'false'
|
WHERE l.data @> '{{ "isExpired": false, "isLegacy": false }}'::jsonb
|
||||||
{searchSql searches}"
|
{searchSql searches}"""
|
||||||
|> Sql.parameters (searches |> List.collect snd)
|
|> Sql.parameters (searches |> List.collect snd)
|
||||||
|> Sql.executeAsync toListingForView
|
|> Sql.executeAsync toListingForView
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ open Npgsql.FSharp
|
|||||||
/// Count the current profiles
|
/// Count the current profiles
|
||||||
let count () =
|
let count () =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"SELECT COUNT(id) AS the_count FROM {Table.Profile} WHERE data ->> 'isLegacy' = 'false'"
|
|> Sql.query
|
||||||
|
$"""SELECT COUNT(id) AS the_count FROM {Table.Profile} WHERE data @> '{{ "isLegacy": false }}'::jsonb"""
|
||||||
|> Sql.executeRowAsync (fun row -> row.int64 "the_count")
|
|> Sql.executeRowAsync (fun row -> row.int64 "the_count")
|
||||||
|
|
||||||
/// Delete a profile by its ID
|
/// Delete a profile by its ID
|
||||||
@@ -40,13 +41,13 @@ let private toProfileForView row =
|
|||||||
let findByIdForView citizenId = backgroundTask {
|
let findByIdForView citizenId = backgroundTask {
|
||||||
let! tryCitizen =
|
let! tryCitizen =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"
|
|> Sql.query $"""
|
||||||
SELECT p.*, c.data AS cit_data, o.data AS cont_data
|
SELECT p.*, c.data AS cit_data, o.data AS cont_data
|
||||||
FROM {Table.Profile} p
|
FROM {Table.Profile} p
|
||||||
INNER JOIN {Table.Citizen} c ON c.id = p.id
|
INNER JOIN {Table.Citizen} c ON c.id = p.id
|
||||||
INNER JOIN {Table.Continent} o ON o.id = p.data ->> 'continentId'
|
INNER JOIN {Table.Continent} o ON o.id = p.data ->> 'continentId'
|
||||||
WHERE p.id = @id
|
WHERE p.id = @id
|
||||||
AND p.data ->> 'isLegacy' = 'false'"
|
AND p.data @> '{{ "isLegacy": false }}'::jsonb"""
|
||||||
|> Sql.parameters [ "@id", Sql.string (CitizenId.toString citizenId) ]
|
|> Sql.parameters [ "@id", Sql.string (CitizenId.toString citizenId) ]
|
||||||
|> Sql.executeAsync toProfileForView
|
|> Sql.executeAsync toProfileForView
|
||||||
return List.tryHead tryCitizen
|
return List.tryHead tryCitizen
|
||||||
@@ -60,26 +61,28 @@ let save (profile : Profile) =
|
|||||||
let search (search : ProfileSearchForm) isPublic = backgroundTask {
|
let search (search : ProfileSearchForm) isPublic = backgroundTask {
|
||||||
let searches = [
|
let searches = [
|
||||||
if search.ContinentId <> "" then
|
if search.ContinentId <> "" then
|
||||||
"p.data ->> 'continentId' = @continentId", [ "@continentId", Sql.string search.ContinentId ]
|
"p.data @> @continent", [ "@continent", Sql.jsonb (mkDoc {| continentId = search.ContinentId |}) ]
|
||||||
if search.RemoteWork <> "" then
|
if search.RemoteWork <> "" then
|
||||||
"p.data ->> 'isRemote' = @remote", [ "@remote", jsonBool (search.RemoteWork = "yes") ]
|
"p.data @> @remote", [ "@remote", Sql.jsonb (mkDoc {| isRemote = search.RemoteWork = "yes" |}) ]
|
||||||
if search.Text <> "" then
|
if search.Text <> "" then
|
||||||
"p.text_search @@ plainto_tsquery(@text_search)", [ "@text_search", Sql.string search.Text ]
|
"p.text_search @@ plainto_tsquery(@text_search)", [ "@text_search", Sql.string search.Text ]
|
||||||
]
|
]
|
||||||
let vizSql =
|
let vizSql =
|
||||||
if isPublic then
|
if isPublic then
|
||||||
sprintf "IN ('%s', '%s')" (ProfileVisibility.toString Public) (ProfileVisibility.toString Anonymous)
|
sprintf "(p.data @> '%s'::jsonb OR p.data @> '%s'::jsonb)"
|
||||||
else sprintf "<> '%s'" (ProfileVisibility.toString Hidden)
|
(mkDoc {| visibility = ProfileVisibility.toString Public |})
|
||||||
|
(mkDoc {| visibility = ProfileVisibility.toString Anonymous |})
|
||||||
|
else sprintf "p.data ->> 'visibility' <> '%s'" (ProfileVisibility.toString Hidden)
|
||||||
let! results =
|
let! results =
|
||||||
dataSource ()
|
dataSource ()
|
||||||
|> Sql.query $"
|
|> Sql.query $"""
|
||||||
SELECT p.*, c.data AS cit_data, o.data AS cont_data
|
SELECT p.*, c.data AS cit_data, o.data AS cont_data
|
||||||
FROM {Table.Profile} p
|
FROM {Table.Profile} p
|
||||||
INNER JOIN {Table.Citizen} c ON c.id = p.id
|
INNER JOIN {Table.Citizen} c ON c.id = p.id
|
||||||
INNER JOIN {Table.Continent} o ON o.id = p.data ->> 'continentId'
|
INNER JOIN {Table.Continent} o ON o.id = p.data ->> 'continentId'
|
||||||
WHERE p.data ->> 'isLegacy' = 'false'
|
WHERE p.data @> '{{ "isLegacy": false }}'::jsonb
|
||||||
AND p.data ->> 'visibility' {vizSql}
|
AND {vizSql}
|
||||||
{searchSql searches}"
|
{searchSql searches}"""
|
||||||
|> Sql.parameters (searches |> List.collect snd)
|
|> Sql.parameters (searches |> List.collect snd)
|
||||||
|> Sql.executeAsync toProfileForView
|
|> Sql.executeAsync toProfileForView
|
||||||
return results |> List.sortBy (fun pfv -> (Citizen.name pfv.Citizen).ToLowerInvariant ())
|
return results |> List.sortBy (fun pfv -> (Citizen.name pfv.Citizen).ToLowerInvariant ())
|
||||||
|
|||||||
@@ -30,4 +30,4 @@ let findById successId =
|
|||||||
|
|
||||||
/// Save a success story
|
/// Save a success story
|
||||||
let save (success : Success) =
|
let save (success : Success) =
|
||||||
dataSource () |> saveDocument Table.Success (SuccessId.toString success.Id) <| mkDoc success
|
(dataSource (), mkDoc success) ||> saveDocument Table.Success (SuccessId.toString success.Id)
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
// vetur.config.js
|
|
||||||
/** @type {import('vls').VeturConfig} */
|
|
||||||
module.exports = {
|
|
||||||
// override vscode settings
|
|
||||||
// Notice: It only affects the settings used by Vetur.
|
|
||||||
settings: {
|
|
||||||
// "vetur.useWorkspaceDependencies": true,
|
|
||||||
// "vetur.experimental.templateInterpolationService": true
|
|
||||||
},
|
|
||||||
projects: [
|
|
||||||
'./src/JobsJobsJobs/App'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user