Convert module funcs to ToString/Parse

This commit is contained in:
Daniel J. Summers 2025-01-30 19:22:45 -05:00
parent 5240b78487
commit facc294d66
9 changed files with 498 additions and 465 deletions

View File

@ -36,9 +36,9 @@ module private Helpers =
IsPublic = row.bool "is_public"
PageSize = row.int "page_size"
TimeZoneId = TimeZoneId (row.string "time_zone_id")
RequestSort = RequestSort.fromCode (row.string "request_sort")
DefaultEmailType = EmailFormat.fromCode (row.string "default_email_type")
AsOfDateDisplay = AsOfDateDisplay.fromCode (row.string "as_of_date_display")
RequestSort = RequestSort.Parse (row.string "request_sort")
DefaultEmailType = EmailFormat.Parse (row.string "default_email_type")
AsOfDateDisplay = AsOfDateDisplay.Parse (row.string "as_of_date_display")
}
/// Map a row to a Member instance
@ -47,7 +47,7 @@ module private Helpers =
SmallGroupId = SmallGroupId (row.uuid "small_group_id")
Name = row.string "member_name"
Email = row.string "email"
Format = row.stringOrNone "email_format" |> Option.map EmailFormat.fromCode
Format = row.stringOrNone "email_format" |> Option.map EmailFormat.Parse
}
/// Map a row to a Prayer Request instance
@ -60,8 +60,8 @@ module private Helpers =
Requestor = row.stringOrNone "requestor"
Text = row.string "request_text"
NotifyChaplain = row.bool "notify_chaplain"
RequestType = PrayerRequestType.fromCode (row.string "request_type")
Expiration = Expiration.fromCode (row.string "expiration")
RequestType = PrayerRequestType.Parse (row.string "request_type")
Expiration = Expiration.Parse (row.string "expiration")
}
/// Map a row to a Small Group instance
@ -185,7 +185,7 @@ module Members =
"@groupId", Sql.uuid mbr.SmallGroupId.Value
"@name", Sql.string mbr.Name
"@email", Sql.string mbr.Email
"@format", Sql.stringOrNone (mbr.Format |> Option.map EmailFormat.toCode) ]
"@format", Sql.stringOrNone (mbr.Format |> Option.map string) ]
/// Retrieve a small group member by its ID
let tryById (memberId : MemberId) =
@ -257,10 +257,10 @@ module PrayerRequests =
OR request_type = @expecting)
AND expiration <> @forced",
[ "@asOf", Sql.parameter asOf
"@manual", Sql.string (Expiration.toCode Manual)
"@longTerm", Sql.string (PrayerRequestType.toCode LongTermRequest)
"@expecting", Sql.string (PrayerRequestType.toCode Expecting)
"@forced", Sql.string (Expiration.toCode Forced) ]
"@manual", Sql.string (string Manual)
"@longTerm", Sql.string (string LongTermRequest)
"@expecting", Sql.string (string Expecting)
"@forced", Sql.string (string Forced) ]
else "", []
Custom.list
$"SELECT *
@ -287,15 +287,15 @@ module PrayerRequests =
notify_chaplain = EXCLUDED.notify_chaplain,
expiration = EXCLUDED.expiration"
[ "@id", Sql.uuid req.Id.Value
"@type", Sql.string (PrayerRequestType.toCode req.RequestType)
"@type", Sql.string (string req.RequestType)
"@userId", Sql.uuid req.UserId.Value
"@groupId", Sql.uuid req.SmallGroupId.Value
"@entered", Sql.parameter (NpgsqlParameter ("@entered", req.EnteredDate))
"@updated", Sql.parameter (NpgsqlParameter ("@updated", req.UpdatedDate))
"@entered", Sql.parameter (NpgsqlParameter("@entered", req.EnteredDate))
"@updated", Sql.parameter (NpgsqlParameter("@updated", req.UpdatedDate))
"@requestor", Sql.stringOrNone req.Requestor
"@text", Sql.string req.Text
"@notifyChaplain", Sql.bool req.NotifyChaplain
"@expiration", Sql.string (Expiration.toCode req.Expiration) ]
"@expiration", Sql.string (string req.Expiration) ]
/// Search prayer requests for the given term
let searchForGroup group searchTerm pageNbr =
@ -320,9 +320,8 @@ module PrayerRequests =
[ "@updated", Sql.parameter (NpgsqlParameter ("@updated", req.UpdatedDate)) ]
else "", []
Custom.nonQuery $"UPDATE pt.prayer_request SET expiration = @expiration{sql} WHERE id = @id"
([ "@expiration", Sql.string (Expiration.toCode req.Expiration)
"@id", Sql.uuid req.Id.Value ]
|> List.append parameters)
([ "@expiration", Sql.string (string req.Expiration); "@id", Sql.uuid req.Id.Value ]
|> List.append parameters)
/// Functions to retrieve small group information
@ -455,13 +454,13 @@ module SmallGroups =
"@lineColor", Sql.string pref.LineColor
"@headingFontSize", Sql.int pref.HeadingFontSize
"@textFontSize", Sql.int pref.TextFontSize
"@requestSort", Sql.string (RequestSort.toCode pref.RequestSort)
"@requestSort", Sql.string (string pref.RequestSort)
"@groupPassword", Sql.string pref.GroupPassword
"@defaultEmailType", Sql.string (EmailFormat.toCode pref.DefaultEmailType)
"@defaultEmailType", Sql.string (string pref.DefaultEmailType)
"@isPublic", Sql.bool pref.IsPublic
"@timeZoneId", Sql.string (TimeZoneId.toString pref.TimeZoneId)
"@pageSize", Sql.int pref.PageSize
"@asOfDateDisplay", Sql.string (AsOfDateDisplay.toCode pref.AsOfDateDisplay) ]
"@asOfDateDisplay", Sql.string (string pref.AsOfDateDisplay) ]
/// Get a small group by its ID
let tryById (groupId : SmallGroupId) =

View File

@ -11,19 +11,20 @@ type AsOfDateDisplay =
/// The as-of date should be displayed in the culture's long date format
| LongDate
/// Functions to support as-of date display options
module AsOfDateDisplay =
/// Convert this to a single-character code
override this.ToString() =
match this with
| NoDisplay -> "N"
| ShortDate -> "S"
| LongDate -> "L"
/// Convert to a DU case from a single-character string
let fromCode code =
/// <summary>Create an <c>AsOfDateDisplay</c> from a single-character code</summary>
static member Parse code =
match code with
| "N" -> NoDisplay
| "S" -> ShortDate
| "L" -> LongDate
| _ -> invalidArg "code" $"Unknown code {code}"
/// Convert this DU case to a single-character string
let toCode = function NoDisplay -> "N" | ShortDate -> "S" | LongDate -> "L"
| _ -> invalidArg "code" $"Unknown code {code}"
/// Acceptable e-mail formats
@ -33,18 +34,18 @@ type EmailFormat =
/// Plain-text e-mail
| PlainTextFormat
/// Functions to support e-mail formats
module EmailFormat =
/// Convert this to a single-character code
override this.ToString() =
match this with
| HtmlFormat -> "H"
| PlainTextFormat -> "P"
/// Convert to a DU case from a single-character string
let fromCode code =
/// <summary>Create an <c>EmailFormat</c> from a single-character code</summary>
static member Parse code =
match code with
| "H" -> HtmlFormat
| "P" -> PlainTextFormat
| _ -> invalidArg "code" $"Unknown code {code}"
/// Convert this DU case to a single-character string
let toCode = function HtmlFormat -> "H" | PlainTextFormat -> "P"
| _ -> invalidArg "code" $"Unknown code {code}"
/// Expiration for requests
@ -56,19 +57,20 @@ type Expiration =
/// Force immediate expiration
| Forced
/// Functions to support expirations
module Expiration =
/// Convert this to a single-character code
override this.ToString() =
match this with
| Automatic -> "A"
| Manual -> "M"
| Forced -> "F"
/// Convert to a DU case from a single-character string
let fromCode code =
/// <summary>Create an <c>Expiration</c> from a single-character code</summary>
static member Parse code =
match code with
| "A" -> Automatic
| "M" -> Manual
| "F" -> Forced
| _ -> invalidArg "code" $"Unknown code {code}"
/// Convert this DU case to a single-character string
let toCode = function Automatic -> "A" | Manual -> "M" | Forced -> "F"
| _ -> invalidArg "code" $"Unknown code {code}"
/// Types of prayer requests
@ -84,27 +86,24 @@ type PrayerRequestType =
/// Announcements
| Announcement
/// Functions to support prayer request types
module PrayerRequestType =
/// Convert this to a single-character code
override this.ToString() =
match this with
| CurrentRequest -> "C"
| LongTermRequest -> "L"
| Expecting -> "E"
| PraiseReport -> "P"
| Announcement -> "A"
/// Convert to a DU case from a single-character string
let fromCode code =
/// <summary>Create a <c>PrayerRequestType</c> from a single-character code</summary>
static member Parse code =
match code with
| "C" -> CurrentRequest
| "L" -> LongTermRequest
| "E" -> Expecting
| "P" -> PraiseReport
| "A" -> Announcement
| _ -> invalidArg "code" $"Unknown code {code}"
/// Convert this DU case to a single-character string
let toCode =
function
| CurrentRequest -> "C"
| LongTermRequest -> "L"
| Expecting -> "E"
| PraiseReport -> "P"
| Announcement -> "A"
| _ -> invalidArg "code" $"Unknown code {code}"
/// How requests should be sorted
@ -114,18 +113,18 @@ type RequestSort =
/// Sort by requestor/subject, then by date
| SortByRequestor
/// Functions to support request sorts
module RequestSort =
/// Convert this to a single-character code
override this.ToString() =
match this with
| SortByDate -> "D"
| SortByRequestor -> "R"
/// Convert to a DU case from a single-character string
let fromCode code =
/// <summary>Create a <c>RequestSort</c> from a single-character code</summary>
static member Parse code =
match code with
| "D" -> SortByDate
| "R" -> SortByRequestor
| _ -> invalidArg "code" $"Unknown code {code}"
/// Convert this DU case to a single-character string
let toCode = function SortByDate -> "D" | SortByRequestor -> "R"
| _ -> invalidArg "code" $"Unknown code {code}"
open System
@ -133,33 +132,45 @@ open System
/// PK type for the Church entity
type ChurchId =
| ChurchId of Guid
with
/// The GUID value of the church ID
member this.Value = this |> function ChurchId guid -> guid
member this.Value =
this
|> function
| ChurchId guid -> guid
/// PK type for the Member entity
type MemberId =
| MemberId of Guid
with
/// The GUID value of the member ID
member this.Value = this |> function MemberId guid -> guid
member this.Value =
this
|> function
| MemberId guid -> guid
/// PK type for the PrayerRequest entity
type PrayerRequestId =
| PrayerRequestId of Guid
with
/// The GUID value of the prayer request ID
member this.Value = this |> function PrayerRequestId guid -> guid
member this.Value =
this
|> function
| PrayerRequestId guid -> guid
/// PK type for the SmallGroup entity
type SmallGroupId =
| SmallGroupId of Guid
with
/// The GUID value of the small group ID
member this.Value = this |> function SmallGroupId guid -> guid
member this.Value =
this
|> function
| SmallGroupId guid -> guid
/// PK type for the TimeZone entity
@ -169,49 +180,56 @@ type TimeZoneId = TimeZoneId of string
module TimeZoneId =
/// Convert a time zone ID to its string value
let toString = function TimeZoneId it -> it
let toString =
function
| TimeZoneId it -> it
/// PK type for the User entity
type UserId =
| UserId of Guid
with
/// The GUID value of the user ID
member this.Value = this |> function UserId guid -> guid
member this.Value =
this
|> function
| UserId guid -> guid
(*-- SPECIFIC VIEW TYPES --*)
/// Statistics for churches
[<NoComparison; NoEquality>]
type ChurchStats =
{ /// The number of small groups in the church
SmallGroups : int
{
/// The number of small groups in the church
SmallGroups: int
/// The number of prayer requests in the church
PrayerRequests : int
PrayerRequests: int
/// The number of users who can access small groups in the church
Users : int
Users: int
}
/// Information needed to display the public/protected request list and small group maintenance pages
[<NoComparison; NoEquality>]
type SmallGroupInfo =
{ /// The ID of the small group
Id : string
{
/// The ID of the small group
Id: string
/// The name of the small group
Name : string
Name: string
/// The name of the church to which the small group belongs
ChurchName : string
ChurchName: string
/// The ID of the time zone for the small group
TimeZoneId : TimeZoneId
TimeZoneId: TimeZoneId
/// Whether the small group has a publicly-available request list
IsPublic : bool
IsPublic: bool
}
(*-- ENTITIES --*)
@ -221,23 +239,24 @@ open NodaTime
/// This represents a church
[<NoComparison; NoEquality>]
type Church =
{ /// The ID of this church
Id : ChurchId
{
/// The ID of this church
Id: ChurchId
/// The name of the church
Name : string
Name: string
/// The city where the church is
City : string
City: string
/// The 2-letter state or province code for the church's location
State : string
State: string
/// Does this church have an active interface with Virtual Prayer Space?
HasVpsInterface : bool
HasVpsInterface: bool
/// The address for the interface
InterfaceAddress : string option
InterfaceAddress: string option
}
/// Functions to support churches
@ -246,123 +265,123 @@ module Church =
/// An empty church
// aww... how sad :(
let empty =
{ Id = ChurchId Guid.Empty
Name = ""
City = ""
State = ""
HasVpsInterface = false
InterfaceAddress = None
}
{ Id = ChurchId Guid.Empty
Name = ""
City = ""
State = ""
HasVpsInterface = false
InterfaceAddress = None }
/// Preferences for the form and format of the prayer request list
[<NoComparison; NoEquality>]
type ListPreferences =
{ /// The Id of the small group to which these preferences belong
SmallGroupId : SmallGroupId
{
/// The Id of the small group to which these preferences belong
SmallGroupId: SmallGroupId
/// The days after which regular requests expire
DaysToExpire : int
DaysToExpire: int
/// The number of days a new or updated request is considered new
DaysToKeepNew : int
DaysToKeepNew: int
/// The number of weeks after which long-term requests are flagged for follow-up
LongTermUpdateWeeks : int
LongTermUpdateWeeks: int
/// The name from which e-mails are sent
EmailFromName : string
EmailFromName: string
/// The e-mail address from which e-mails are sent
EmailFromAddress : string
EmailFromAddress: string
/// The fonts to use in generating the list of prayer requests
Fonts : string
Fonts: string
/// The color for the prayer request list headings
HeadingColor : string
HeadingColor: string
/// The color for the lines offsetting the prayer request list headings
LineColor : string
LineColor: string
/// The font size for the headings on the prayer request list
HeadingFontSize : int
HeadingFontSize: int
/// The font size for the text on the prayer request list
TextFontSize : int
TextFontSize: int
/// The order in which the prayer requests are sorted
RequestSort : RequestSort
RequestSort: RequestSort
/// The password used for "small group login" (view-only request list)
GroupPassword : string
GroupPassword: string
/// The default e-mail type for this class
DefaultEmailType : EmailFormat
DefaultEmailType: EmailFormat
/// Whether this class makes its request list public
IsPublic : bool
IsPublic: bool
/// The time zone which this class uses (use tzdata names)
TimeZoneId : TimeZoneId
TimeZoneId: TimeZoneId
/// The number of requests displayed per page
PageSize : int
PageSize: int
/// How the as-of date should be automatically displayed
AsOfDateDisplay : AsOfDateDisplay
AsOfDateDisplay: AsOfDateDisplay
}
with
/// The list of fonts to use when displaying request lists (converts "native" to native font stack)
member this.FontStack =
if this.Fonts = "native" then
"""system-ui,-apple-system,"Segoe UI",Roboto,Ubuntu,"Liberation Sans",Cantarell,"Helvetica Neue",sans-serif"""
else this.Fonts
else
this.Fonts
/// Functions to support list preferences
module ListPreferences =
/// A set of preferences with their default values
let empty =
{ SmallGroupId = SmallGroupId Guid.Empty
DaysToExpire = 14
DaysToKeepNew = 7
LongTermUpdateWeeks = 4
EmailFromName = "PrayerTracker"
EmailFromAddress = "prayer@bitbadger.solutions"
Fonts = "native"
HeadingColor = "maroon"
LineColor = "navy"
HeadingFontSize = 16
TextFontSize = 12
RequestSort = SortByDate
GroupPassword = ""
DefaultEmailType = HtmlFormat
IsPublic = false
TimeZoneId = TimeZoneId "America/Denver"
PageSize = 100
AsOfDateDisplay = NoDisplay
}
{ SmallGroupId = SmallGroupId Guid.Empty
DaysToExpire = 14
DaysToKeepNew = 7
LongTermUpdateWeeks = 4
EmailFromName = "PrayerTracker"
EmailFromAddress = "prayer@bitbadger.solutions"
Fonts = "native"
HeadingColor = "maroon"
LineColor = "navy"
HeadingFontSize = 16
TextFontSize = 12
RequestSort = SortByDate
GroupPassword = ""
DefaultEmailType = HtmlFormat
IsPublic = false
TimeZoneId = TimeZoneId "America/Denver"
PageSize = 100
AsOfDateDisplay = NoDisplay }
/// A member of a small group
[<NoComparison; NoEquality>]
type Member =
{ /// The ID of the small group member
Id : MemberId
{
/// The ID of the small group member
Id: MemberId
/// The Id of the small group to which this member belongs
SmallGroupId : SmallGroupId
SmallGroupId: SmallGroupId
/// The name of the member
Name : string
Name: string
/// The e-mail address for the member
Email : string
Email: string
/// The type of e-mail preferred by this member
Format : EmailFormat option
Format: EmailFormat option
}
/// Functions to support small group members
@ -370,46 +389,46 @@ module Member =
/// An empty member
let empty =
{ Id = MemberId Guid.Empty
SmallGroupId = SmallGroupId Guid.Empty
Name = ""
Email = ""
Format = None
}
{ Id = MemberId Guid.Empty
SmallGroupId = SmallGroupId Guid.Empty
Name = ""
Email = ""
Format = None }
/// This represents a single prayer request
[<NoComparison; NoEquality>]
type PrayerRequest =
{ /// The ID of this request
Id : PrayerRequestId
{
/// The ID of this request
Id: PrayerRequestId
/// The type of the request
RequestType : PrayerRequestType
RequestType: PrayerRequestType
/// The ID of the user who entered the request
UserId : UserId
UserId: UserId
/// The small group to which this request belongs
SmallGroupId : SmallGroupId
SmallGroupId: SmallGroupId
/// The date/time on which this request was entered
EnteredDate : Instant
EnteredDate: Instant
/// The date/time this request was last updated
UpdatedDate : Instant
UpdatedDate: Instant
/// The name of the requestor or subject, or title of announcement
Requestor : string option
Requestor: string option
/// The text of the request
Text : string
Text: string
/// Whether the chaplain should be notified for this request
NotifyChaplain : bool
NotifyChaplain: bool
/// Is this request expired?
Expiration : Expiration
Expiration: Expiration
}
// functions are below small group functions
@ -417,17 +436,18 @@ type PrayerRequest =
/// This represents a small group (Sunday School class, Bible study group, etc.)
[<NoComparison; NoEquality>]
type SmallGroup =
{ /// The ID of this small group
Id : SmallGroupId
{
/// The ID of this small group
Id: SmallGroupId
/// The church to which this group belongs
ChurchId : ChurchId
ChurchId: ChurchId
/// The name of the group
Name : string
Name: string
/// The preferences for the request list
Preferences : ListPreferences
Preferences: ListPreferences
}
/// Functions to support small groups
@ -435,26 +455,29 @@ module SmallGroup =
/// An empty small group
let empty =
{ Id = SmallGroupId Guid.Empty
ChurchId = ChurchId Guid.Empty
Name = ""
Preferences = ListPreferences.empty
}
{ Id = SmallGroupId Guid.Empty
ChurchId = ChurchId Guid.Empty
Name = ""
Preferences = ListPreferences.empty }
/// The DateTimeZone for the time zone ID for this small group
let timeZone group =
let tzId = TimeZoneId.toString group.Preferences.TimeZoneId
if DateTimeZoneProviders.Tzdb.Ids.Contains tzId then DateTimeZoneProviders.Tzdb[tzId]
else DateTimeZone.Utc
if DateTimeZoneProviders.Tzdb.Ids.Contains tzId then
DateTimeZoneProviders.Tzdb[tzId]
else
DateTimeZone.Utc
/// Get the local date/time for this group
let localTimeNow (clock : IClock) group =
if isNull clock then nullArg (nameof clock)
let localTimeNow (clock: IClock) group =
if isNull clock then
nullArg (nameof clock)
clock.GetCurrentInstant().InZone(timeZone group).LocalDateTime
/// Get the local date for this group
let localDateNow clock group =
(localTimeNow clock group).Date
let localDateNow clock group = (localTimeNow clock group).Date
/// Functions to support prayer requests
@ -462,89 +485,92 @@ module PrayerRequest =
/// An empty request
let empty =
{ Id = PrayerRequestId Guid.Empty
RequestType = CurrentRequest
UserId = UserId Guid.Empty
SmallGroupId = SmallGroupId Guid.Empty
EnteredDate = Instant.MinValue
UpdatedDate = Instant.MinValue
Requestor = None
Text = ""
NotifyChaplain = false
Expiration = Automatic
}
{ Id = PrayerRequestId Guid.Empty
RequestType = CurrentRequest
UserId = UserId Guid.Empty
SmallGroupId = SmallGroupId Guid.Empty
EnteredDate = Instant.MinValue
UpdatedDate = Instant.MinValue
Requestor = None
Text = ""
NotifyChaplain = false
Expiration = Automatic }
/// Is this request expired?
let isExpired (asOf : LocalDate) group req =
let isExpired (asOf: LocalDate) group req =
match req.Expiration, req.RequestType with
| Forced, _ -> true
| Manual, _
| Automatic, LongTermRequest
| Automatic, Expecting -> false
| Automatic, Expecting -> false
| Automatic, _ ->
// Automatic expiration
Period.Between(req.UpdatedDate.InZone(SmallGroup.timeZone group).Date, asOf, PeriodUnits.Days).Days
>= group.Preferences.DaysToExpire
Period
.Between(req.UpdatedDate.InZone(SmallGroup.timeZone group).Date, asOf, PeriodUnits.Days)
.Days
>= group.Preferences.DaysToExpire
/// Is an update required for this long-term request?
let updateRequired asOf group req =
if isExpired asOf group req then false
else asOf.PlusWeeks -group.Preferences.LongTermUpdateWeeks
>= req.UpdatedDate.InZone(SmallGroup.timeZone group).Date
if isExpired asOf group req then
false
else
asOf.PlusWeeks -group.Preferences.LongTermUpdateWeeks
>= req.UpdatedDate.InZone(SmallGroup.timeZone group).Date
/// This represents a user of PrayerTracker
[<NoComparison; NoEquality>]
type User =
{ /// The ID of this user
Id : UserId
{
/// The ID of this user
Id: UserId
/// The first name of this user
FirstName : string
FirstName: string
/// The last name of this user
LastName : string
LastName: string
/// The e-mail address of the user
Email : string
Email: string
/// Whether this user is a PrayerTracker system administrator
IsAdmin : bool
IsAdmin: bool
/// The user's hashed password
PasswordHash : string
PasswordHash: string
/// The last time the user was seen (set whenever the user is loaded into a session)
LastSeen : Instant option
LastSeen: Instant option
}
with
/// The full name of the user
member this.Name =
$"{this.FirstName} {this.LastName}"
member this.Name = $"{this.FirstName} {this.LastName}"
/// Functions to support users
module User =
/// An empty user
let empty =
{ Id = UserId Guid.Empty
FirstName = ""
LastName = ""
Email = ""
IsAdmin = false
PasswordHash = ""
LastSeen = None
}
{ Id = UserId Guid.Empty
FirstName = ""
LastName = ""
Email = ""
IsAdmin = false
PasswordHash = ""
LastSeen = None }
/// Cross-reference between user and small group
[<NoComparison; NoEquality>]
type UserSmallGroup =
{ /// The Id of the user who has access to the small group
UserId : UserId
{
/// The Id of the user who has access to the small group
UserId: UserId
/// The Id of the small group to which the user has access
SmallGroupId : SmallGroupId
SmallGroupId: SmallGroupId
}
/// Functions to support user/small group cross-reference
@ -552,6 +578,5 @@ module UserSmallGroup =
/// An empty user/small group xref
let empty =
{ UserId = UserId Guid.Empty
SmallGroupId = SmallGroupId Guid.Empty
}
{ UserId = UserId Guid.Empty
SmallGroupId = SmallGroupId Guid.Empty }

View File

@ -8,28 +8,32 @@ open System
[<Tests>]
let asOfDateDisplayTests =
testList "AsOfDateDisplay" [
test "NoDisplay code is correct" {
Expect.equal (AsOfDateDisplay.toCode NoDisplay) "N" "The code for NoDisplay should have been \"N\""
}
test "ShortDate code is correct" {
Expect.equal (AsOfDateDisplay.toCode ShortDate) "S" "The code for ShortDate should have been \"S\""
}
test "LongDate code is correct" {
Expect.equal (AsOfDateDisplay.toCode LongDate) "L" "The code for LongDate should have been \"N\""
}
test "fromCode N should return NoDisplay" {
Expect.equal (AsOfDateDisplay.fromCode "N") NoDisplay "\"N\" should have been converted to NoDisplay"
}
test "fromCode S should return ShortDate" {
Expect.equal (AsOfDateDisplay.fromCode "S") ShortDate "\"S\" should have been converted to ShortDate"
}
test "fromCode L should return LongDate" {
Expect.equal (AsOfDateDisplay.fromCode "L") LongDate "\"L\" should have been converted to LongDate"
}
test "fromCode X should raise" {
Expect.throws (fun () -> AsOfDateDisplay.fromCode "X" |> ignore)
"An unknown code should have raised an exception"
}
testList "ToString" [
test "NoDisplay code is correct" {
Expect.equal (string NoDisplay) "N" "The code for NoDisplay should have been \"N\""
}
test "ShortDate code is correct" {
Expect.equal (string ShortDate) "S" "The code for ShortDate should have been \"S\""
}
test "LongDate code is correct" {
Expect.equal (string LongDate) "L" "The code for LongDate should have been \"N\""
}
]
testList "Parse" [
test "N should return NoDisplay" {
Expect.equal (AsOfDateDisplay.Parse "N") NoDisplay "\"N\" should have been parsed to NoDisplay"
}
test "S should return ShortDate" {
Expect.equal (AsOfDateDisplay.Parse "S") ShortDate "\"S\" should have been parsed to ShortDate"
}
test "L should return LongDate" {
Expect.equal (AsOfDateDisplay.Parse "L") LongDate "\"L\" should have been parsed to LongDate"
}
test "X should raise" {
Expect.throws (fun () -> AsOfDateDisplay.Parse "X" |> ignore)
"An unknown code should have raised an exception"
}
]
]
[<Tests>]
@ -49,50 +53,58 @@ let churchTests =
[<Tests>]
let emailFormatTests =
testList "EmailFormat" [
test "HtmlFormat code is correct" {
Expect.equal (EmailFormat.toCode HtmlFormat) "H" "The code for HtmlFormat should have been \"H\""
}
test "PlainTextFormat code is correct" {
Expect.equal (EmailFormat.toCode PlainTextFormat) "P" "The code for PlainTextFormat should have been \"P\""
}
test "fromCode H should return HtmlFormat" {
Expect.equal (EmailFormat.fromCode "H") HtmlFormat "\"H\" should have been converted to HtmlFormat"
}
test "fromCode P should return ShortDate" {
Expect.equal (EmailFormat.fromCode "P") PlainTextFormat
"\"P\" should have been converted to PlainTextFormat"
}
test "fromCode Z should raise" {
Expect.throws (fun () -> EmailFormat.fromCode "Z" |> ignore)
"An unknown code should have raised an exception"
}
testList "ToString" [
test "HtmlFormat code is correct" {
Expect.equal (string HtmlFormat) "H" "The code for HtmlFormat should have been \"H\""
}
test "PlainTextFormat code is correct" {
Expect.equal (string PlainTextFormat) "P" "The code for PlainTextFormat should have been \"P\""
}
]
testList "Parse" [
test "H should return HtmlFormat" {
Expect.equal (EmailFormat.Parse "H") HtmlFormat "\"H\" should have been converted to HtmlFormat"
}
test "P should return ShortDate" {
Expect.equal (EmailFormat.Parse "P") PlainTextFormat
"\"P\" should have been converted to PlainTextFormat"
}
test "Z should raise" {
Expect.throws (fun () -> EmailFormat.Parse "Z" |> ignore)
"An unknown code should have raised an exception"
}
]
]
[<Tests>]
let expirationTests =
testList "Expiration" [
test "Automatic code is correct" {
Expect.equal (Expiration.toCode Automatic) "A" "The code for Automatic should have been \"A\""
}
test "Manual code is correct" {
Expect.equal (Expiration.toCode Manual) "M" "The code for Manual should have been \"M\""
}
test "Forced code is correct" {
Expect.equal (Expiration.toCode Forced) "F" "The code for Forced should have been \"F\""
}
test "fromCode A should return Automatic" {
Expect.equal (Expiration.fromCode "A") Automatic "\"A\" should have been converted to Automatic"
}
test "fromCode M should return Manual" {
Expect.equal (Expiration.fromCode "M") Manual "\"M\" should have been converted to Manual"
}
test "fromCode F should return Forced" {
Expect.equal (Expiration.fromCode "F") Forced "\"F\" should have been converted to Forced"
}
test "fromCode V should raise" {
Expect.throws (fun () -> Expiration.fromCode "V" |> ignore)
"An unknown code should have raised an exception"
}
testList "ToString" [
test "Automatic code is correct" {
Expect.equal (string Automatic) "A" "The code for Automatic should have been \"A\""
}
test "Manual code is correct" {
Expect.equal (string Manual) "M" "The code for Manual should have been \"M\""
}
test "Forced code is correct" {
Expect.equal (string Forced) "F" "The code for Forced should have been \"F\""
}
]
testList "Parse" [
test "A should return Automatic" {
Expect.equal (Expiration.Parse "A") Automatic "\"A\" should have been converted to Automatic"
}
test "M should return Manual" {
Expect.equal (Expiration.Parse "M") Manual "\"M\" should have been converted to Manual"
}
test "F should return Forced" {
Expect.equal (Expiration.Parse "F") Forced "\"F\" should have been converted to Forced"
}
test "fromCode V should raise" {
Expect.throws (fun () -> Expiration.Parse "V" |> ignore)
"An unknown code should have raised an exception"
}
]
]
[<Tests>]
@ -223,68 +235,74 @@ let prayerRequestTests =
[<Tests>]
let prayerRequestTypeTests =
testList "PrayerRequestType" [
test "CurrentRequest code is correct" {
Expect.equal (PrayerRequestType.toCode CurrentRequest) "C"
"The code for CurrentRequest should have been \"C\""
}
test "LongTermRequest code is correct" {
Expect.equal (PrayerRequestType.toCode LongTermRequest) "L"
"The code for LongTermRequest should have been \"L\""
}
test "PraiseReport code is correct" {
Expect.equal (PrayerRequestType.toCode PraiseReport) "P" "The code for PraiseReport should have been \"P\""
}
test "Expecting code is correct" {
Expect.equal (PrayerRequestType.toCode Expecting) "E" "The code for Expecting should have been \"E\""
}
test "Announcement code is correct" {
Expect.equal (PrayerRequestType.toCode Announcement) "A" "The code for Announcement should have been \"A\""
}
test "fromCode C should return CurrentRequest" {
Expect.equal (PrayerRequestType.fromCode "C") CurrentRequest
"\"C\" should have been converted to CurrentRequest"
}
test "fromCode L should return LongTermRequest" {
Expect.equal (PrayerRequestType.fromCode "L") LongTermRequest
"\"L\" should have been converted to LongTermRequest"
}
test "fromCode P should return PraiseReport" {
Expect.equal (PrayerRequestType.fromCode "P") PraiseReport
"\"P\" should have been converted to PraiseReport"
}
test "fromCode E should return Expecting" {
Expect.equal (PrayerRequestType.fromCode "E") Expecting "\"E\" should have been converted to Expecting"
}
test "fromCode A should return Announcement" {
Expect.equal (PrayerRequestType.fromCode "A") Announcement
"\"A\" should have been converted to Announcement"
}
test "fromCode R should raise" {
Expect.throws (fun () -> PrayerRequestType.fromCode "R" |> ignore)
"An unknown code should have raised an exception"
}
testList "ToString" [
test "CurrentRequest code is correct" {
Expect.equal (string CurrentRequest) "C" "The code for CurrentRequest should have been \"C\""
}
test "LongTermRequest code is correct" {
Expect.equal (string LongTermRequest) "L" "The code for LongTermRequest should have been \"L\""
}
test "PraiseReport code is correct" {
Expect.equal (string PraiseReport) "P" "The code for PraiseReport should have been \"P\""
}
test "Expecting code is correct" {
Expect.equal (string Expecting) "E" "The code for Expecting should have been \"E\""
}
test "Announcement code is correct" {
Expect.equal (string Announcement) "A" "The code for Announcement should have been \"A\""
}
]
testList "Parse" [
test "C should return CurrentRequest" {
Expect.equal (PrayerRequestType.Parse "C") CurrentRequest
"\"C\" should have been converted to CurrentRequest"
}
test "L should return LongTermRequest" {
Expect.equal (PrayerRequestType.Parse "L") LongTermRequest
"\"L\" should have been converted to LongTermRequest"
}
test "P should return PraiseReport" {
Expect.equal (PrayerRequestType.Parse "P") PraiseReport
"\"P\" should have been converted to PraiseReport"
}
test "E should return Expecting" {
Expect.equal (PrayerRequestType.Parse "E") Expecting "\"E\" should have been converted to Expecting"
}
test "A should return Announcement" {
Expect.equal (PrayerRequestType.Parse "A") Announcement
"\"A\" should have been converted to Announcement"
}
test "R should raise" {
Expect.throws (fun () -> PrayerRequestType.Parse "R" |> ignore)
"An unknown code should have raised an exception"
}
]
]
[<Tests>]
let requestSortTests =
testList "RequestSort" [
test "SortByDate code is correct" {
Expect.equal (RequestSort.toCode SortByDate) "D" "The code for SortByDate should have been \"D\""
}
test "SortByRequestor code is correct" {
Expect.equal (RequestSort.toCode SortByRequestor) "R" "The code for SortByRequestor should have been \"R\""
}
test "fromCode D should return SortByDate" {
Expect.equal (RequestSort.fromCode "D") SortByDate "\"D\" should have been converted to SortByDate"
}
test "fromCode R should return SortByRequestor" {
Expect.equal (RequestSort.fromCode "R") SortByRequestor
"\"R\" should have been converted to SortByRequestor"
}
test "fromCode Q should raise" {
Expect.throws (fun () -> RequestSort.fromCode "Q" |> ignore)
"An unknown code should have raised an exception"
}
testList "ToString" [
test "SortByDate code is correct" {
Expect.equal (string SortByDate) "D" "The code for SortByDate should have been \"D\""
}
test "SortByRequestor code is correct" {
Expect.equal (string SortByRequestor) "R" "The code for SortByRequestor should have been \"R\""
}
]
testList "Parse" [
test "D should return SortByDate" {
Expect.equal (RequestSort.Parse "D") SortByDate "\"D\" should have been converted to SortByDate"
}
test "R should return SortByRequestor" {
Expect.equal (RequestSort.Parse "R") SortByRequestor
"\"R\" should have been converted to SortByRequestor"
}
test "Q should raise" {
Expect.throws (fun () -> RequestSort.Parse "Q" |> ignore)
"An unknown code should have raised an exception"
}
]
]
[<Tests>]

View File

@ -22,12 +22,9 @@ module ReferenceListTests =
test "has all three options listed" {
let asOf = ReferenceList.asOfDateList _s
Expect.hasCountOf asOf 3u countAll "There should have been 3 as-of choices returned"
Expect.exists asOf (fun (x, _) -> x = AsOfDateDisplay.toCode NoDisplay)
"The option for no display was not found"
Expect.exists asOf (fun (x, _) -> x = AsOfDateDisplay.toCode ShortDate)
"The option for a short date was not found"
Expect.exists asOf (fun (x, _) -> x = AsOfDateDisplay.toCode LongDate)
"The option for a full date was not found"
Expect.exists asOf (fun (x, _) -> x = string NoDisplay) "The option for no display was not found"
Expect.exists asOf (fun (x, _) -> x = string ShortDate) "The option for a short date was not found"
Expect.exists asOf (fun (x, _) -> x = string LongDate) "The option for a full date was not found"
}
]
@ -41,9 +38,9 @@ module ReferenceListTests =
Expect.equal (fst top) "" "The default option should have been blank"
Expect.equal (snd top).Value "Group Default (HTML Format)" "The default option label was incorrect"
let nxt = typs |> Seq.skip 1 |> Seq.head
Expect.equal (fst nxt) (EmailFormat.toCode HtmlFormat) "The 2nd option should have been HTML"
Expect.equal (fst nxt) (string HtmlFormat) "The 2nd option should have been HTML"
let lst = typs |> Seq.last
Expect.equal (fst lst) (EmailFormat.toCode PlainTextFormat) "The 3rd option should have been plain text"
Expect.equal (fst lst) (string PlainTextFormat) "The 3rd option should have been plain text"
}
]
@ -53,19 +50,19 @@ module ReferenceListTests =
test "excludes immediate expiration if not required" {
let exps = ReferenceList.expirationList _s false
Expect.hasCountOf exps 2u countAll "There should have been 2 expiration types returned"
Expect.exists exps (fun (exp, _) -> exp = Expiration.toCode Automatic)
Expect.exists exps (fun (exp, _) -> exp = string Automatic)
"The option for automatic expiration was not found"
Expect.exists exps (fun (exp, _) -> exp = Expiration.toCode Manual)
Expect.exists exps (fun (exp, _) -> exp = string Manual)
"The option for manual expiration was not found"
}
test "includes immediate expiration if required" {
let exps = ReferenceList.expirationList _s true
Expect.hasCountOf exps 3u countAll "There should have been 3 expiration types returned"
Expect.exists exps (fun (exp, _) -> exp = Expiration.toCode Automatic)
Expect.exists exps (fun (exp, _) -> exp = string Automatic)
"The option for automatic expiration was not found"
Expect.exists exps (fun (exp, _) -> exp = Expiration.toCode Manual)
Expect.exists exps (fun (exp, _) -> exp = string Manual)
"The option for manual expiration was not found"
Expect.exists exps (fun (exp, _) -> exp = Expiration.toCode Forced)
Expect.exists exps (fun (exp, _) -> exp = string Forced)
"The option for immediate expiration was not found"
}
]
@ -240,7 +237,7 @@ let editMemberTests =
}
test "fromMember populates with specific format" {
let edit = EditMember.fromMember { Member.empty with Format = Some HtmlFormat }
Expect.equal edit.Format (EmailFormat.toCode HtmlFormat) "The e-mail format was not filled correctly"
Expect.equal edit.Format (string HtmlFormat) "The e-mail format was not filled correctly"
}
test "empty is as expected" {
let edit = EditMember.empty
@ -268,11 +265,10 @@ let editPreferencesTests =
Expect.equal edit.DaysToKeepNew prefs.DaysToKeepNew "The days to keep new were not filled correctly"
Expect.equal edit.LongTermUpdateWeeks prefs.LongTermUpdateWeeks
"The weeks for update were not filled correctly"
Expect.equal edit.RequestSort (RequestSort.toCode prefs.RequestSort)
"The request sort was not filled correctly"
Expect.equal edit.RequestSort (string prefs.RequestSort) "The request sort was not filled correctly"
Expect.equal edit.EmailFromName prefs.EmailFromName "The e-mail from name was not filled correctly"
Expect.equal edit.EmailFromAddress prefs.EmailFromAddress "The e-mail from address was not filled correctly"
Expect.equal edit.DefaultEmailType (EmailFormat.toCode prefs.DefaultEmailType)
Expect.equal edit.DefaultEmailType (string prefs.DefaultEmailType)
"The default e-mail type was not filled correctly"
Expect.equal edit.LineColorType "Name" "The heading line color type was not derived correctly"
Expect.equal edit.LineColor prefs.LineColor "The heading line color was not filled correctly"
@ -288,8 +284,7 @@ let editPreferencesTests =
Expect.equal edit.Visibility GroupVisibility.PrivateList
"The list visibility was not derived correctly"
Expect.equal edit.PageSize prefs.PageSize "The page size was not filled correctly"
Expect.equal edit.AsOfDate (AsOfDateDisplay.toCode prefs.AsOfDateDisplay)
"The as-of date display was not filled correctly"
Expect.equal edit.AsOfDate (string prefs.AsOfDateDisplay) "The as-of date display was not filled correctly"
}
test "fromPreferences succeeds for RGB line color and password-protected list" {
let prefs = { ListPreferences.empty with LineColor = "#ff0000"; GroupPassword = "pw" }
@ -326,13 +321,11 @@ let editRequestTests =
test "empty is as expected" {
let mt = EditRequest.empty
Expect.equal mt.RequestId emptyGuid "The request ID should be an empty GUID"
Expect.equal mt.RequestType (PrayerRequestType.toCode CurrentRequest)
"The request type should have been \"Current\""
Expect.equal mt.RequestType (string CurrentRequest) "The request type should have been \"Current\""
Expect.isNone mt.EnteredDate "The entered date should have been None"
Expect.isNone mt.SkipDateUpdate """The "skip date update" flag should have been None"""
Expect.isNone mt.Requestor "The requestor should have been None"
Expect.equal mt.Expiration (Expiration.toCode Automatic)
"""The expiration should have been "A" (Automatic)"""
Expect.equal mt.Expiration (string Automatic) """The expiration should have been "A" (Automatic)"""
Expect.equal mt.Text "" "The text should have been blank"
}
test "fromRequest succeeds" {
@ -346,10 +339,9 @@ let editRequestTests =
}
let edit = EditRequest.fromRequest req
Expect.equal edit.RequestId (shortGuid req.Id.Value) "The request ID was not filled correctly"
Expect.equal edit.RequestType (PrayerRequestType.toCode req.RequestType)
"The request type was not filled correctly"
Expect.equal edit.RequestType (string req.RequestType) "The request type was not filled correctly"
Expect.equal edit.Requestor req.Requestor "The requestor was not filled correctly"
Expect.equal edit.Expiration (Expiration.toCode Manual) "The expiration was not filled correctly"
Expect.equal edit.Expiration (string Manual) "The expiration was not filled correctly"
Expect.equal edit.Text req.Text "The text was not filled correctly"
}
test "isNew works for a new request" {

View File

@ -29,7 +29,7 @@ let edit (model : EditRequest) today ctx viewInfo =
label [ _for (nameof model.RequestType) ] [ locStr s["Request Type"] ]
ReferenceList.requestTypeList s
|> Seq.ofList
|> Seq.map (fun (typ, desc) -> PrayerRequestType.toCode typ, desc.Value)
|> Seq.map (fun (typ, desc) -> string typ, desc.Value)
|> selectList (nameof model.RequestType) model.RequestType [ _required; _autofocus ]
]
div [ _inputField ] [

View File

@ -54,8 +54,8 @@ let announcement isAdmin ctx viewInfo =
label [ _for (nameof model.RequestType) ] [ locStr s["Request Type"] ]
reqTypes
|> Seq.ofList
|> Seq.map (fun (typ, desc) -> PrayerRequestType.toCode typ, desc.Value)
|> selectList (nameof model.RequestType) (PrayerRequestType.toCode Announcement) []
|> Seq.map (fun (typ, desc) -> string typ, desc.Value)
|> selectList (nameof model.RequestType) (string Announcement) []
]
]
div [ _fieldRow ] [ submit [] "send" s["Send Announcement"] ]
@ -273,7 +273,7 @@ let members (members : Member list) (emailTypes : Map<string, LocalizedString>)
div [ _class "cell" ] [ str mbr.Name ]
div [ _class "cell" ] [ str mbr.Email ]
div [ _class "cell" ] [
locStr emailTypes[defaultArg (mbr.Format |> Option.map EmailFormat.toCode) ""]
locStr emailTypes[defaultArg (mbr.Format |> Option.map string) ""]
]
]
]

View File

@ -11,9 +11,9 @@ module ReferenceList =
/// A localized list of the AsOfDateDisplay DU cases
let asOfDateList (s: IStringLocalizer) = [
AsOfDateDisplay.toCode NoDisplay, s["Do not display the “as of” date"]
AsOfDateDisplay.toCode ShortDate, s["Display a short “as of” date"]
AsOfDateDisplay.toCode LongDate, s["Display a full “as of” date"]
string NoDisplay, s["Do not display the “as of” date"]
string ShortDate, s["Display a short “as of” date"]
string LongDate, s["Display a full “as of” date"]
]
/// A list of e-mail type options
@ -23,16 +23,15 @@ module ReferenceList =
s[match def with HtmlFormat -> "HTML Format" | PlainTextFormat -> "Plain-Text Format"].Value
seq {
"", LocalizedString ("", $"""{s["Group Default"].Value} ({defaultType})""")
EmailFormat.toCode HtmlFormat, s["HTML Format"]
EmailFormat.toCode PlainTextFormat, s["Plain-Text Format"]
string HtmlFormat, s["HTML Format"]
string PlainTextFormat, s["Plain-Text Format"]
}
/// A list of expiration options
let expirationList (s: IStringLocalizer) includeExpireNow = [
Expiration.toCode Automatic, s["Expire Normally"]
Expiration.toCode Manual, s["Request Never Expires"]
if includeExpireNow then Expiration.toCode Forced, s["Expire Immediately"]
]
let expirationList (s: IStringLocalizer) includeExpireNow =
[ string Automatic, s["Expire Normally"]
string Manual, s["Request Never Expires"]
if includeExpireNow then string Forced, s["Expire Immediately"] ]
/// A list of request types
let requestTypeList (s: IStringLocalizer) = [
@ -326,7 +325,7 @@ module EditMember =
{ MemberId = shortGuid mbr.Id.Value
Name = mbr.Name
Email = mbr.Email
Format = match mbr.Format with Some fmt -> EmailFormat.toCode fmt | None -> ""
Format = mbr.Format |> Option.map string |> Option.defaultValue ""
}
/// An empty instance
@ -413,10 +412,10 @@ with
DaysToExpire = this.ExpireDays
DaysToKeepNew = this.DaysToKeepNew
LongTermUpdateWeeks = this.LongTermUpdateWeeks
RequestSort = RequestSort.fromCode this.RequestSort
RequestSort = RequestSort.Parse this.RequestSort
EmailFromName = this.EmailFromName
EmailFromAddress = this.EmailFromAddress
DefaultEmailType = EmailFormat.fromCode this.DefaultEmailType
DefaultEmailType = EmailFormat.Parse this.DefaultEmailType
LineColor = this.LineColor
HeadingColor = this.HeadingColor
Fonts = if this.IsNative || Option.isNone this.Fonts then "native" else this.Fonts.Value
@ -426,7 +425,7 @@ with
IsPublic = isPublic
GroupPassword = grpPw
PageSize = this.PageSize
AsOfDateDisplay = AsOfDateDisplay.fromCode this.AsOfDate
AsOfDateDisplay = AsOfDateDisplay.Parse this.AsOfDate
}
/// Support for the EditPreferences type
@ -437,10 +436,10 @@ module EditPreferences =
{ ExpireDays = prefs.DaysToExpire
DaysToKeepNew = prefs.DaysToKeepNew
LongTermUpdateWeeks = prefs.LongTermUpdateWeeks
RequestSort = RequestSort.toCode prefs.RequestSort
RequestSort = string prefs.RequestSort
EmailFromName = prefs.EmailFromName
EmailFromAddress = prefs.EmailFromAddress
DefaultEmailType = EmailFormat.toCode prefs.DefaultEmailType
DefaultEmailType = string prefs.DefaultEmailType
LineColorType = setType prefs.LineColor
LineColor = prefs.LineColor
HeadingColorType = setType prefs.HeadingColor
@ -452,7 +451,7 @@ module EditPreferences =
TimeZone = TimeZoneId.toString prefs.TimeZoneId
GroupPassword = Some prefs.GroupPassword
PageSize = prefs.PageSize
AsOfDate = AsOfDateDisplay.toCode prefs.AsOfDateDisplay
AsOfDate = string prefs.AsOfDateDisplay
Visibility =
if prefs.IsPublic then GroupVisibility.PublicList
elif prefs.GroupPassword = "" then GroupVisibility.PrivateList
@ -495,11 +494,11 @@ module EditRequest =
/// An empty instance to use for new requests
let empty =
{ RequestId = emptyGuid
RequestType = PrayerRequestType.toCode CurrentRequest
RequestType = string CurrentRequest
EnteredDate = None
SkipDateUpdate = None
Requestor = None
Expiration = Expiration.toCode Automatic
Expiration = string Automatic
Text = ""
}
@ -507,9 +506,9 @@ module EditRequest =
let fromRequest (req: PrayerRequest) =
{ empty with
RequestId = shortGuid req.Id.Value
RequestType = PrayerRequestType.toCode req.RequestType
RequestType = string req.RequestType
Requestor = req.Requestor
Expiration = Expiration.toCode req.Expiration
Expiration = string req.Expiration
Text = req.Text
}

View File

@ -238,10 +238,10 @@ let save : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun next ct
let now = SmallGroup.localDateNow ctx.Clock group
let updated =
{ pr with
RequestType = PrayerRequestType.fromCode model.RequestType
RequestType = PrayerRequestType.Parse model.RequestType
Requestor = match model.Requestor with Some x when x.Trim() = "" -> None | x -> x
Text = ckEditorToText model.Text
Expiration = Expiration.fromCode model.Expiration
Expiration = Expiration.Parse model.Expiration
}
|> function
| it when model.IsNew ->

View File

@ -210,7 +210,7 @@ let saveMember : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun n
{ mbr with
Name = model.Name
Email = model.Email
Format = String.noneIfBlank model.Format |> Option.map EmailFormat.fromCode }
Format = String.noneIfBlank model.Format |> Option.map EmailFormat.Parse }
let act = ctx.Strings[if model.IsNew then "Added" else "Updated"].Value.ToLower()
addInfo ctx ctx.Strings["Successfully {0} group member", act]
return! redirectTo false "/small-group/members" next ctx
@ -288,7 +288,7 @@ let sendAnnouncement : HttpHandler = requireAccess [ User ] >=> validateCsrf >=>
Id = (Guid.NewGuid >> PrayerRequestId) ()
SmallGroupId = group.Id
UserId = usr.Id
RequestType = (Option.get >> PrayerRequestType.fromCode) model.RequestType
RequestType = (Option.get >> PrayerRequestType.Parse) model.RequestType
Text = requestText
EnteredDate = now.Date.AtStartOfDayInZone(zone).ToInstant()
UpdatedDate = now.InZoneLeniently(zone).ToInstant() }