Update dates for help and legal pages
- Switch to containment queries for exact matches - Bump version to 3.0.1
This commit is contained in:
parent
e3f3baa13f
commit
f8cdd393ff
|
@ -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.string 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)."
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ type DistributedCache () =
|
||||||
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
|
||||||
|
|
|
@ -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.1.0</AssemblyVersion>
|
||||||
<FileVersion>3.0.0.0</FileVersion>
|
<FileVersion>3.0.1.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" ]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user