Implement hidden visibility (#39)

This commit is contained in:
Daniel J. Summers 2023-01-29 16:02:36 -05:00
parent acfb6f50c7
commit ff68864879
3 changed files with 36 additions and 16 deletions

View File

@ -159,6 +159,8 @@ type OtherContact =
/// Visibility options for an employment profile
type ProfileVisibility =
/// Profile is only visible to the citizen to whom it belongs
| Hidden
/// Profile is only visible to authenticated users
| Private
/// Anonymous information is visible to public users
@ -172,6 +174,7 @@ module ProfileVisibility =
/// Parse a string into a profile visibility
let parse viz =
match viz with
| "Hidden" -> Hidden
| "Private" -> Private
| "Anonymous" -> Anonymous
| "Public" -> Public
@ -180,6 +183,7 @@ module ProfileVisibility =
/// Convert a profile visibility to its string representation
let toString =
function
| Hidden -> "Hidden"
| Private -> "Private"
| Anonymous -> "Anonymous"
| Public -> "Public"

View File

@ -209,31 +209,38 @@ let deleteHistory idx : HttpHandler = requireUser >=> validateCsrf >=> fun next
| None -> return! notFound ctx
}
// GET: /profile/[id]/view
let view citizenId : HttpHandler = fun next ctx -> task {
/// Get a profile for view, and enforce visibility restrictions against the current user
let private getProfileForView citizenId ctx = task {
let citId = CitizenId citizenId
match! Data.findByIdForView citId with
| Some profile ->
let currentCitizen = tryUser ctx |> Option.map CitizenId.ofString
if not (profile.Profile.Visibility = Public) && Option.isNone currentCitizen then
return! Error.notAuthorized next ctx
else
let title = $"Employment Profile for {Citizen.name profile.Citizen}"
return! Views.view profile currentCitizen |> render title next ctx
let canView =
match profile.Profile.Visibility, currentCitizen with
| Private, Some _
| Anonymous, Some _
| Public, _ -> true
| Hidden, Some citizenId when profile.Citizen.Id = citizenId -> true
| _ -> false
return if canView then Some (profile, currentCitizen) else None
| None -> return None
}
// GET: /profile/[id]/view
let view citizenId : HttpHandler = fun next ctx -> task {
match! getProfileForView citizenId ctx with
| Some (profile, currentCitizen) ->
let title = $"Employment Profile for {Citizen.name profile.Citizen}"
return! Views.view profile currentCitizen |> render title next ctx
| None -> return! notFound ctx
}
// GET: /profile/[id]/print
let print citizenId : HttpHandler = fun next ctx -> task {
let citId = CitizenId citizenId
match! Data.findByIdForView citId with
| Some profile ->
let currentCitizen = tryUser ctx |> Option.map CitizenId.ofString
if not (profile.Profile.Visibility = Public) && Option.isNone currentCitizen then
return! Error.notAuthorized next ctx
else
let pageTitle = $"Employment Profile for {Citizen.name profile.Citizen}"
return! Views.print profile (Option.isNone currentCitizen) |> renderPrint pageTitle next ctx
match! getProfileForView citizenId ctx with
| Some (profile, currentCitizen) ->
let pageTitle = $"Employment Profile for {Citizen.name profile.Citizen}"
return! Views.print profile (Option.isNone currentCitizen) |> renderPrint pageTitle next ctx
| None -> return! notFound ctx
}

View File

@ -102,6 +102,15 @@ let editGeneralInfo (m : EditProfileForm) continents isHtmx csrf =
div [ _class "col-12" ] [
hr []
h4 [] [ txt "Visibility" ]
div [ _class "form-check" ] [
let hid = ProfileVisibility.toString Hidden
input [ _type "radio"; _id $"{nameof m.Visibility}Hidden"; _name (nameof m.Visibility)
_class "form-check-input"; _value hid; if m.Visibility = hid then _checked ]
label [ _class "form-check-label"; _for $"{nameof m.Visibility}Hidden" ] [
strong [] [ txt "Hidden" ]
txt " – do not show my employment profile to anyone else"
]
]
div [ _class "form-check" ] [
let pvt = ProfileVisibility.toString Private
input [ _type "radio"; _id $"{nameof m.Visibility}Private"; _name (nameof m.Visibility)