Convert module funcs to ToString/Parse
This commit is contained in:
parent
5240b78487
commit
facc294d66
@ -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) =
|
||||
|
@ -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 to a DU case from a single-character string
|
||||
let fromCode code =
|
||||
/// Convert this to a single-character code
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| NoDisplay -> "N"
|
||||
| ShortDate -> "S"
|
||||
| LongDate -> "L"
|
||||
|
||||
/// <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 to a DU case from a single-character string
|
||||
let fromCode code =
|
||||
/// Convert this to a single-character code
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| HtmlFormat -> "H"
|
||||
| PlainTextFormat -> "P"
|
||||
|
||||
/// <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 to a DU case from a single-character string
|
||||
let fromCode code =
|
||||
/// Convert this to a single-character code
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| Automatic -> "A"
|
||||
| Manual -> "M"
|
||||
| Forced -> "F"
|
||||
|
||||
/// <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 to a DU case from a single-character string
|
||||
let fromCode code =
|
||||
/// Convert this to a single-character code
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| CurrentRequest -> "C"
|
||||
| LongTermRequest -> "L"
|
||||
| Expecting -> "E"
|
||||
| PraiseReport -> "P"
|
||||
| Announcement -> "A"
|
||||
|
||||
/// <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 to a DU case from a single-character string
|
||||
let fromCode code =
|
||||
/// Convert this to a single-character code
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| SortByDate -> "D"
|
||||
| SortByRequestor -> "R"
|
||||
|
||||
/// <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
|
||||
@ -167,51 +178,58 @@ type TimeZoneId = TimeZoneId of string
|
||||
|
||||
/// Functions to support time zone IDs
|
||||
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,195 +239,196 @@ 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
|
||||
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
|
||||
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,141 +436,147 @@ 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
|
||||
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
|
||||
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, _
|
||||
| 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
|
||||
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 }
|
||||
|
@ -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>]
|
||||
|
@ -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" {
|
||||
|
@ -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 ] [
|
||||
|
@ -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) ""]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 ->
|
||||
|
@ -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() }
|
||||
|
Loading…
x
Reference in New Issue
Block a user