Version 3 #40
|
@ -410,7 +410,7 @@
|
|||
<hr>
|
||||
|
||||
<p class="fst-italic">
|
||||
Changes on August 30<sup>th</sup>, 2022 –
|
||||
Changes on August 30<sup>th</sup>, 2022
|
||||
</p>
|
||||
<ul>
|
||||
<li class="fst-italic">Removed references to Mastodon</li>
|
||||
|
|
|
@ -335,7 +335,7 @@ module Listings =
|
|||
|
||||
/// Map a result for a listing view
|
||||
let private toListingForView row =
|
||||
{ listing = toDocument<Listing> row; continent = toDocumentFrom<Continent> "cont_data" row }
|
||||
{ Listing = toDocument<Listing> row; Continent = toDocumentFrom<Continent> "cont_data" row }
|
||||
|
||||
/// Find all job listings posted by the given citizen
|
||||
let findByCitizen citizenId =
|
||||
|
@ -369,15 +369,15 @@ module Listings =
|
|||
/// Search job listings
|
||||
let search (search : ListingSearch) =
|
||||
let searches = [
|
||||
match search.continentId with
|
||||
match search.ContinentId with
|
||||
| Some contId -> "l.data ->> 'continentId' = @continentId", [ "@continentId", Sql.string contId ]
|
||||
| None -> ()
|
||||
match search.region with
|
||||
match search.Region with
|
||||
| Some region -> "l.data ->> 'region' ILIKE @region", [ "@region", like region ]
|
||||
| None -> ()
|
||||
if search.remoteWork <> "" then
|
||||
"l.data ->> 'isRemote' = @remote", [ "@remote", jsonBool (search.remoteWork = "yes") ]
|
||||
match search.text with
|
||||
if search.RemoteWork <> "" then
|
||||
"l.data ->> 'isRemote' = @remote", [ "@remote", jsonBool (search.RemoteWork = "yes") ]
|
||||
match search.Text with
|
||||
| Some text -> "l.data ->> 'text' ILIKE @text", [ "@text", like text ]
|
||||
| None -> ()
|
||||
]
|
||||
|
@ -431,9 +431,9 @@ module Profiles =
|
|||
AND p.data ->> 'isLegacy' = 'false'"
|
||||
|> Sql.parameters [ "@id", Sql.string (CitizenId.toString citizenId) ]
|
||||
|> Sql.executeAsync (fun row ->
|
||||
{ profile = toDocument<Profile> row
|
||||
citizen = toDocumentFrom<Citizen> "cit_data" row
|
||||
continent = toDocumentFrom<Continent> "cont_data" row
|
||||
{ Profile = toDocument<Profile> row
|
||||
Citizen = toDocumentFrom<Citizen> "cit_data" row
|
||||
Continent = toDocumentFrom<Continent> "cont_data" row
|
||||
})
|
||||
return List.tryHead tryCitizen
|
||||
}
|
||||
|
@ -445,15 +445,15 @@ module Profiles =
|
|||
/// Search profiles (logged-on users)
|
||||
let search (search : ProfileSearch) = backgroundTask {
|
||||
let searches = [
|
||||
match search.continentId with
|
||||
match search.ContinentId with
|
||||
| Some contId -> "p.data ->> 'continentId' = @continentId", [ "@continentId", Sql.string contId ]
|
||||
| None -> ()
|
||||
if search.remoteWork <> "" then
|
||||
"p.data ->> 'remoteWork' = @remote", [ "@remote", jsonBool (search.remoteWork = "yes") ]
|
||||
match search.skill with
|
||||
if search.RemoteWork <> "" then
|
||||
"p.data ->> 'remoteWork' = @remote", [ "@remote", jsonBool (search.RemoteWork = "yes") ]
|
||||
match search.Skill with
|
||||
| Some skl -> "p.data -> 'skills' ->> 'description' ILIKE @description", [ "@description", like skl ]
|
||||
| None -> ()
|
||||
match search.bioExperience with
|
||||
match search.BioExperience with
|
||||
| Some text ->
|
||||
"(p.data ->> 'biography' ILIKE @text OR p.data ->> 'experience' ILIKE @text)",
|
||||
[ "@text", Sql.string text ]
|
||||
|
@ -471,28 +471,28 @@ module Profiles =
|
|||
|> Sql.executeAsync (fun row ->
|
||||
let profile = toDocument<Profile> row
|
||||
let citizen = toDocumentFrom<Citizen> "cit_data" row
|
||||
{ citizenId = profile.Id
|
||||
displayName = Citizen.name citizen
|
||||
seekingEmployment = profile.IsSeekingEmployment
|
||||
remoteWork = profile.IsRemote
|
||||
fullTime = profile.IsFullTime
|
||||
lastUpdatedOn = profile.LastUpdatedOn
|
||||
{ CitizenId = profile.Id
|
||||
DisplayName = Citizen.name citizen
|
||||
SeekingEmployment = profile.IsSeekingEmployment
|
||||
RemoteWork = profile.IsRemote
|
||||
FullTime = profile.IsFullTime
|
||||
LastUpdatedOn = profile.LastUpdatedOn
|
||||
})
|
||||
return results |> List.sortBy (fun psr -> psr.displayName.ToLowerInvariant ())
|
||||
return results |> List.sortBy (fun psr -> psr.DisplayName.ToLowerInvariant ())
|
||||
}
|
||||
|
||||
// Search profiles (public)
|
||||
let publicSearch (search : PublicSearch) =
|
||||
let searches = [
|
||||
match search.continentId with
|
||||
match search.ContinentId with
|
||||
| Some contId -> "p.data ->> 'continentId' = @continentId", [ "@continentId", Sql.string contId ]
|
||||
| None -> ()
|
||||
match search.region with
|
||||
match search.Region with
|
||||
| Some region -> "p.data ->> 'region' ILIKE @region", [ "@region", like region ]
|
||||
| None -> ()
|
||||
if search.remoteWork <> "" then
|
||||
"p.data ->> 'remoteWork' = @remote", [ "@remote", jsonBool (search.remoteWork = "yes") ]
|
||||
match search.skill with
|
||||
if search.RemoteWork <> "" then
|
||||
"p.data ->> 'remoteWork' = @remote", [ "@remote", jsonBool (search.RemoteWork = "yes") ]
|
||||
match search.Skill with
|
||||
| Some skl ->
|
||||
"p.data -> 'skills' ->> 'description' ILIKE @description", [ "@description", like skl ]
|
||||
| None -> ()
|
||||
|
@ -508,10 +508,10 @@ module Profiles =
|
|||
|> Sql.executeAsync (fun row ->
|
||||
let profile = toDocument<Profile> row
|
||||
let continent = toDocumentFrom<Continent> "cont_data" row
|
||||
{ continent = continent.Name
|
||||
region = profile.Region
|
||||
remoteWork = profile.IsRemote
|
||||
skills = profile.Skills
|
||||
{ Continent = continent.Name
|
||||
Region = profile.Region
|
||||
RemoteWork = profile.IsRemote
|
||||
Skills = profile.Skills
|
||||
|> List.map (fun s ->
|
||||
let notes = match s.Notes with Some n -> $" ({n})" | None -> ""
|
||||
$"{s.Description}{notes}")
|
||||
|
@ -532,12 +532,12 @@ module Successes =
|
|||
|> Sql.executeAsync (fun row ->
|
||||
let success = toDocument<Success> row
|
||||
let citizen = toDocumentFrom<Citizen> "cit_data" row
|
||||
{ id = success.Id
|
||||
citizenId = success.CitizenId
|
||||
citizenName = Citizen.name citizen
|
||||
recordedOn = success.RecordedOn
|
||||
fromHere = success.IsFromHere
|
||||
hasStory = Option.isSome success.Story
|
||||
{ Id = success.Id
|
||||
CitizenId = success.CitizenId
|
||||
CitizenName = Citizen.name citizen
|
||||
RecordedOn = success.RecordedOn
|
||||
FromHere = success.IsFromHere
|
||||
HasStory = Option.isSome success.Story
|
||||
})
|
||||
|
||||
/// Find a success story by its ID
|
||||
|
|
|
@ -5,8 +5,6 @@ open JobsJobsJobs.Domain
|
|||
open Microsoft.Extensions.Options
|
||||
open NodaTime
|
||||
|
||||
// fsharplint:disable FieldNames
|
||||
|
||||
/// The data required to register a new citizen (user)
|
||||
type CitizenRegistrationForm =
|
||||
{ /// The first name of the new citizen
|
||||
|
@ -31,45 +29,45 @@ type CitizenRegistrationForm =
|
|||
/// The data required to add or edit a job listing
|
||||
type ListingForm =
|
||||
{ /// The ID of the listing
|
||||
id : string
|
||||
Id : string
|
||||
|
||||
/// The listing title
|
||||
title : string
|
||||
Title : string
|
||||
|
||||
/// The ID of the continent on which this opportunity exists
|
||||
continentId : string
|
||||
ContinentId : string
|
||||
|
||||
/// The region in which this opportunity exists
|
||||
region : string
|
||||
Region : string
|
||||
|
||||
/// Whether this is a remote work opportunity
|
||||
remoteWork : bool
|
||||
RemoteWork : bool
|
||||
|
||||
/// The text of the job listing
|
||||
text : string
|
||||
Text : string
|
||||
|
||||
/// The date by which this job listing is needed
|
||||
neededBy : string option
|
||||
NeededBy : string option
|
||||
}
|
||||
|
||||
|
||||
/// The data needed to display a listing
|
||||
type ListingForView =
|
||||
{ /// The listing itself
|
||||
listing : Listing
|
||||
Listing : Listing
|
||||
|
||||
/// The continent for that listing
|
||||
continent : Continent
|
||||
Continent : Continent
|
||||
}
|
||||
|
||||
|
||||
/// The form submitted to expire a listing
|
||||
type ListingExpireForm =
|
||||
{ /// Whether the job was filled from here
|
||||
fromHere : bool
|
||||
FromHere : bool
|
||||
|
||||
/// The success story written by the user
|
||||
successStory : string option
|
||||
SuccessStory : string option
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,46 +75,39 @@ type ListingExpireForm =
|
|||
[<CLIMutable>]
|
||||
type ListingSearch =
|
||||
{ /// Retrieve job listings for this continent
|
||||
continentId : string option
|
||||
ContinentId : string option
|
||||
|
||||
/// Text for a search within a region
|
||||
region : string option
|
||||
Region : string option
|
||||
|
||||
/// Whether to retrieve job listings for remote work
|
||||
remoteWork : string
|
||||
RemoteWork : string
|
||||
|
||||
/// Text for a search with the job listing description
|
||||
text : string option
|
||||
Text : string option
|
||||
}
|
||||
|
||||
|
||||
/// The fields needed to log on to Jobs, Jobs, Jobs
|
||||
type LogOnForm =
|
||||
{ /// The e-mail address for the citizen
|
||||
email : string
|
||||
Email : string
|
||||
|
||||
/// The password provided by the user
|
||||
password : string
|
||||
Password : string
|
||||
}
|
||||
|
||||
|
||||
/// A successful logon
|
||||
type LogOnSuccess =
|
||||
{ /// The JSON Web Token (JWT) to use for API access
|
||||
jwt : string
|
||||
Jwt : string
|
||||
|
||||
/// The ID of the logged-in citizen (as a string)
|
||||
citizenId : string
|
||||
CitizenId : string
|
||||
|
||||
/// The name of the logged-in citizen
|
||||
name : string
|
||||
}
|
||||
|
||||
|
||||
/// A count
|
||||
type Count =
|
||||
{ // The count being returned
|
||||
count : int64
|
||||
Name : string
|
||||
}
|
||||
|
||||
|
||||
|
@ -133,44 +124,44 @@ type AuthOptions () =
|
|||
/// The fields required for a skill
|
||||
type SkillForm =
|
||||
{ /// The ID of this skill
|
||||
id : string
|
||||
Id : string
|
||||
|
||||
/// The description of the skill
|
||||
description : string
|
||||
Description : string
|
||||
|
||||
/// Notes regarding the skill
|
||||
notes : string option
|
||||
Notes : string option
|
||||
}
|
||||
|
||||
/// The data required to update a profile
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type ProfileForm =
|
||||
{ /// Whether the citizen to whom this profile belongs is actively seeking employment
|
||||
isSeekingEmployment : bool
|
||||
IsSeekingEmployment : bool
|
||||
|
||||
/// Whether this profile should appear in the public search
|
||||
isPublic : bool
|
||||
IsPublic : bool
|
||||
|
||||
/// The ID of the continent on which the citizen is located
|
||||
continentId : string
|
||||
ContinentId : string
|
||||
|
||||
/// The area within that continent where the citizen is located
|
||||
region : string
|
||||
Region : string
|
||||
|
||||
/// If the citizen is available for remote work
|
||||
remoteWork : bool
|
||||
RemoteWork : bool
|
||||
|
||||
/// If the citizen is seeking full-time employment
|
||||
fullTime : bool
|
||||
FullTime : bool
|
||||
|
||||
/// The user's professional biography
|
||||
biography : string
|
||||
Biography : string
|
||||
|
||||
/// The user's past experience
|
||||
experience : string option
|
||||
Experience : string option
|
||||
|
||||
/// The skills for the user
|
||||
skills : SkillForm list
|
||||
Skills : SkillForm list
|
||||
}
|
||||
|
||||
/// Support functions for the ProfileForm type
|
||||
|
@ -178,19 +169,19 @@ module ProfileForm =
|
|||
|
||||
/// Create an instance of this form from the given profile
|
||||
let fromProfile (profile : Profile) =
|
||||
{ isSeekingEmployment = profile.IsSeekingEmployment
|
||||
isPublic = profile.IsPubliclySearchable
|
||||
continentId = string profile.ContinentId
|
||||
region = profile.Region
|
||||
remoteWork = profile.IsRemote
|
||||
fullTime = profile.IsFullTime
|
||||
biography = MarkdownString.toString profile.Biography
|
||||
experience = profile.Experience |> Option.map MarkdownString.toString
|
||||
skills = profile.Skills
|
||||
{ IsSeekingEmployment = profile.IsSeekingEmployment
|
||||
IsPublic = profile.IsPubliclySearchable
|
||||
ContinentId = string profile.ContinentId
|
||||
Region = profile.Region
|
||||
RemoteWork = profile.IsRemote
|
||||
FullTime = profile.IsFullTime
|
||||
Biography = MarkdownString.toString profile.Biography
|
||||
Experience = profile.Experience |> Option.map MarkdownString.toString
|
||||
Skills = profile.Skills
|
||||
|> List.map (fun s ->
|
||||
{ id = string s.Id
|
||||
description = s.Description
|
||||
notes = s.Notes
|
||||
{ Id = string s.Id
|
||||
Description = s.Description
|
||||
Notes = s.Notes
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -199,51 +190,51 @@ module ProfileForm =
|
|||
[<CLIMutable>]
|
||||
type ProfileSearch =
|
||||
{ /// Retrieve citizens from this continent
|
||||
continentId : string option
|
||||
ContinentId : string option
|
||||
|
||||
/// Text for a search within a citizen's skills
|
||||
skill : string option
|
||||
Skill : string option
|
||||
|
||||
/// Text for a search with a citizen's professional biography and experience fields
|
||||
bioExperience : string option
|
||||
BioExperience : string option
|
||||
|
||||
/// Whether to retrieve citizens who do or do not want remote work
|
||||
remoteWork : string
|
||||
RemoteWork : string
|
||||
}
|
||||
|
||||
|
||||
/// A user matching the profile search
|
||||
type ProfileSearchResult =
|
||||
{ /// The ID of the citizen
|
||||
citizenId : CitizenId
|
||||
CitizenId : CitizenId
|
||||
|
||||
/// The citizen's display name
|
||||
displayName : string
|
||||
DisplayName : string
|
||||
|
||||
/// Whether this citizen is currently seeking employment
|
||||
seekingEmployment : bool
|
||||
SeekingEmployment : bool
|
||||
|
||||
/// Whether this citizen is looking for remote work
|
||||
remoteWork : bool
|
||||
RemoteWork : bool
|
||||
|
||||
/// Whether this citizen is looking for full-time work
|
||||
fullTime : bool
|
||||
FullTime : bool
|
||||
|
||||
/// When this profile was last updated
|
||||
lastUpdatedOn : Instant
|
||||
LastUpdatedOn : Instant
|
||||
}
|
||||
|
||||
|
||||
/// The data required to show a viewable profile
|
||||
type ProfileForView =
|
||||
{ /// The profile itself
|
||||
profile : Profile
|
||||
Profile : Profile
|
||||
|
||||
/// The citizen to whom the profile belongs
|
||||
citizen : Citizen
|
||||
Citizen : Citizen
|
||||
|
||||
/// The continent for the profile
|
||||
continent : Continent
|
||||
Continent : Continent
|
||||
}
|
||||
|
||||
|
||||
|
@ -251,25 +242,26 @@ type ProfileForView =
|
|||
[<CLIMutable>]
|
||||
type PublicSearch =
|
||||
{ /// Retrieve citizens from this continent
|
||||
continentId : string option
|
||||
ContinentId : string option
|
||||
|
||||
/// Retrieve citizens from this region
|
||||
region : string option
|
||||
Region : string option
|
||||
|
||||
/// Text for a search within a citizen's skills
|
||||
skill : string option
|
||||
Skill : string option
|
||||
|
||||
/// Whether to retrieve citizens who do or do not want remote work
|
||||
remoteWork : string
|
||||
RemoteWork : string
|
||||
}
|
||||
|
||||
/// Support functions for public searches
|
||||
module PublicSearch =
|
||||
/// Is the search empty?
|
||||
let isEmptySearch (search : PublicSearch) =
|
||||
[ search.continentId
|
||||
search.skill
|
||||
match search.remoteWork with "" -> Some search.remoteWork | _ -> None
|
||||
[ search.ContinentId
|
||||
search.Region
|
||||
search.Skill
|
||||
if search.RemoteWork = "" then Some search.RemoteWork else None
|
||||
]
|
||||
|> List.exists Option.isSome
|
||||
|
||||
|
@ -277,49 +269,49 @@ module PublicSearch =
|
|||
/// A public profile search result
|
||||
type PublicSearchResult =
|
||||
{ /// The name of the continent on which the citizen resides
|
||||
continent : string
|
||||
Continent : string
|
||||
|
||||
/// The region in which the citizen resides
|
||||
region : string
|
||||
Region : string
|
||||
|
||||
/// Whether this citizen is seeking remote work
|
||||
remoteWork : bool
|
||||
RemoteWork : bool
|
||||
|
||||
/// The skills this citizen has identified
|
||||
skills : string list
|
||||
Skills : string list
|
||||
}
|
||||
|
||||
|
||||
/// The data required to provide a success story
|
||||
type StoryForm =
|
||||
{ /// The ID of this story
|
||||
id : string
|
||||
Id : string
|
||||
|
||||
/// Whether the employment was obtained from Jobs, Jobs, Jobs
|
||||
fromHere : bool
|
||||
FromHere : bool
|
||||
|
||||
/// The success story
|
||||
story : string
|
||||
Story : string
|
||||
}
|
||||
|
||||
|
||||
/// An entry in the list of success stories
|
||||
type StoryEntry =
|
||||
{ /// The ID of this success story
|
||||
id : SuccessId
|
||||
Id : SuccessId
|
||||
|
||||
/// The ID of the citizen who recorded this story
|
||||
citizenId : CitizenId
|
||||
CitizenId : CitizenId
|
||||
|
||||
/// The name of the citizen who recorded this story
|
||||
citizenName : string
|
||||
CitizenName : string
|
||||
|
||||
/// When this story was recorded
|
||||
recordedOn : Instant
|
||||
RecordedOn : Instant
|
||||
|
||||
/// Whether this story involves an opportunity that arose due to Jobs, Jobs, Jobs
|
||||
fromHere : bool
|
||||
FromHere : bool
|
||||
|
||||
/// Whether this report has a further story, or if it is simply a "found work" entry
|
||||
hasStory : bool
|
||||
HasStory : bool
|
||||
}
|
||||
|
|
|
@ -78,10 +78,23 @@ module MarkdownString =
|
|||
let toString = function Text text -> text
|
||||
|
||||
|
||||
/// Types of contacts supported by Jobs, Jobs, Jobs
|
||||
type ContactType =
|
||||
/// E-mail addresses
|
||||
| Email
|
||||
/// Phone numbers (home, work, cell, etc.)
|
||||
| Phone
|
||||
/// Websites (personal, social, etc.)
|
||||
| Website
|
||||
|
||||
|
||||
/// Another way to contact a citizen from this site
|
||||
type OtherContact =
|
||||
{ /// The name of the contact (Email, No Agenda Social, LinkedIn, etc.)
|
||||
Name : string
|
||||
{ /// The type of contact
|
||||
ContactType : ContactType
|
||||
|
||||
/// The name of the contact (Email, No Agenda Social, LinkedIn, etc.)
|
||||
Name : string option
|
||||
|
||||
/// The value for the contact (e-mail address, user name, URL, etc.)
|
||||
Value : string
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
open NodaTime
|
||||
open System
|
||||
|
||||
// fsharplint:disable FieldNames
|
||||
|
||||
/// A user of Jobs, Jobs, Jobs; a citizen of Gitmo Nation
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type Citizen =
|
||||
|
|
|
@ -144,26 +144,26 @@ module Citizen =
|
|||
let confirmToken : HttpHandler = fun next ctx -> task {
|
||||
let! form = ctx.BindJsonAsync<{| token : string |}> ()
|
||||
let! valid = Citizens.confirmAccount form.token
|
||||
return! json {| valid = valid |} next ctx
|
||||
return! json {| Valid = valid |} next ctx
|
||||
}
|
||||
|
||||
// DELETE: /api/citizen/deny
|
||||
let denyToken : HttpHandler = fun next ctx -> task {
|
||||
let! form = ctx.BindJsonAsync<{| token : string |}> ()
|
||||
let! valid = Citizens.denyAccount form.token
|
||||
return! json {| valid = valid |} next ctx
|
||||
return! json {| Valid = valid |} next ctx
|
||||
}
|
||||
|
||||
// POST: /api/citizen/log-on
|
||||
let logOn : HttpHandler = fun next ctx -> task {
|
||||
let! form = ctx.BindJsonAsync<LogOnForm> ()
|
||||
match! Citizens.tryLogOn form.email form.password Auth.Passwords.verify Auth.Passwords.hash (now ctx) with
|
||||
match! Citizens.tryLogOn form.Email form.Password Auth.Passwords.verify Auth.Passwords.hash (now ctx) with
|
||||
| Ok citizen ->
|
||||
return!
|
||||
json
|
||||
{ jwt = Auth.createJwt citizen (authConfig ctx)
|
||||
citizenId = CitizenId.toString citizen.Id
|
||||
name = Citizen.name citizen
|
||||
{ Jwt = Auth.createJwt citizen (authConfig ctx)
|
||||
CitizenId = CitizenId.toString citizen.Id
|
||||
Name = Citizen.name citizen
|
||||
} next ctx
|
||||
| Error msg -> return! RequestErrors.BAD_REQUEST msg next ctx
|
||||
}
|
||||
|
@ -228,14 +228,14 @@ module Listing =
|
|||
Id = ListingId.create ()
|
||||
CitizenId = currentCitizenId ctx
|
||||
CreatedOn = now
|
||||
Title = form.title
|
||||
ContinentId = ContinentId.ofString form.continentId
|
||||
Region = form.region
|
||||
IsRemote = form.remoteWork
|
||||
Title = form.Title
|
||||
ContinentId = ContinentId.ofString form.ContinentId
|
||||
Region = form.Region
|
||||
IsRemote = form.RemoteWork
|
||||
IsExpired = false
|
||||
UpdatedOn = now
|
||||
Text = Text form.text
|
||||
NeededBy = (form.neededBy |> Option.map parseDate)
|
||||
Text = Text form.Text
|
||||
NeededBy = (form.NeededBy |> Option.map parseDate)
|
||||
WasFilledHere = None
|
||||
IsLegacy = false
|
||||
}
|
||||
|
@ -250,12 +250,12 @@ module Listing =
|
|||
let! form = ctx.BindJsonAsync<ListingForm> ()
|
||||
do! Listings.save
|
||||
{ listing with
|
||||
Title = form.title
|
||||
ContinentId = ContinentId.ofString form.continentId
|
||||
Region = form.region
|
||||
IsRemote = form.remoteWork
|
||||
Text = Text form.text
|
||||
NeededBy = form.neededBy |> Option.map parseDate
|
||||
Title = form.Title
|
||||
ContinentId = ContinentId.ofString form.ContinentId
|
||||
Region = form.Region
|
||||
IsRemote = form.RemoteWork
|
||||
Text = Text form.Text
|
||||
NeededBy = form.NeededBy |> Option.map parseDate
|
||||
UpdatedOn = now ctx
|
||||
}
|
||||
return! ok next ctx
|
||||
|
@ -272,16 +272,16 @@ module Listing =
|
|||
do! Listings.save
|
||||
{ listing with
|
||||
IsExpired = true
|
||||
WasFilledHere = Some form.fromHere
|
||||
WasFilledHere = Some form.FromHere
|
||||
UpdatedOn = now
|
||||
}
|
||||
match form.successStory with
|
||||
match form.SuccessStory with
|
||||
| Some storyText ->
|
||||
do! Successes.save
|
||||
{ Id = SuccessId.create()
|
||||
CitizenId = currentCitizenId ctx
|
||||
RecordedOn = now
|
||||
IsFromHere = form.fromHere
|
||||
IsFromHere = form.FromHere
|
||||
Source = "listing"
|
||||
Story = (Text >> Some) storyText
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ module Profile =
|
|||
// GET: /api/profile/count
|
||||
let count : HttpHandler = authorize >=> fun next ctx -> task {
|
||||
let! theCount = Profiles.count ()
|
||||
return! json { count = theCount } next ctx
|
||||
return! json {| Count = theCount |} next ctx
|
||||
}
|
||||
|
||||
// POST: /api/profile/save
|
||||
|
@ -342,21 +342,21 @@ module Profile =
|
|||
}
|
||||
do! Profiles.save
|
||||
{ profile with
|
||||
IsSeekingEmployment = form.isSeekingEmployment
|
||||
IsPubliclySearchable = form.isPublic
|
||||
ContinentId = ContinentId.ofString form.continentId
|
||||
Region = form.region
|
||||
IsRemote = form.remoteWork
|
||||
IsFullTime = form.fullTime
|
||||
Biography = Text form.biography
|
||||
IsSeekingEmployment = form.IsSeekingEmployment
|
||||
IsPubliclySearchable = form.IsPublic
|
||||
ContinentId = ContinentId.ofString form.ContinentId
|
||||
Region = form.Region
|
||||
IsRemote = form.RemoteWork
|
||||
IsFullTime = form.FullTime
|
||||
Biography = Text form.Biography
|
||||
LastUpdatedOn = now ctx
|
||||
Experience = noneIfBlank form.experience |> Option.map Text
|
||||
Skills = form.skills
|
||||
Experience = noneIfBlank form.Experience |> Option.map Text
|
||||
Skills = form.Skills
|
||||
|> List.map (fun s ->
|
||||
{ Id = if s.id.StartsWith "new" then SkillId.create ()
|
||||
else SkillId.ofString s.id
|
||||
Description = s.description
|
||||
Notes = noneIfBlank s.notes
|
||||
{ Id = if s.Id.StartsWith "new" then SkillId.create ()
|
||||
else SkillId.ofString s.Id
|
||||
Description = s.Description
|
||||
Notes = noneIfBlank s.Notes
|
||||
})
|
||||
}
|
||||
return! ok next ctx
|
||||
|
@ -414,21 +414,21 @@ module Success =
|
|||
let citizenId = currentCitizenId ctx
|
||||
let! form = ctx.BindJsonAsync<StoryForm> ()
|
||||
let! success = task {
|
||||
match form.id with
|
||||
match form.Id with
|
||||
| "new" ->
|
||||
return Some { Id = SuccessId.create ()
|
||||
CitizenId = citizenId
|
||||
RecordedOn = now ctx
|
||||
IsFromHere = form.fromHere
|
||||
IsFromHere = form.FromHere
|
||||
Source = "profile"
|
||||
Story = noneIfEmpty form.story |> Option.map Text
|
||||
Story = noneIfEmpty form.Story |> Option.map Text
|
||||
}
|
||||
| successId ->
|
||||
match! Successes.findById (SuccessId.ofString successId) with
|
||||
| Some story when story.CitizenId = citizenId ->
|
||||
return Some { story with
|
||||
IsFromHere = form.fromHere
|
||||
Story = noneIfEmpty form.story |> Option.map Text
|
||||
IsFromHere = form.FromHere
|
||||
Story = noneIfEmpty form.Story |> Option.map Text
|
||||
}
|
||||
| Some _ | None -> return None
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user