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" |             IsPublic            = row.bool     "is_public" | ||||||
|             PageSize            = row.int      "page_size" |             PageSize            = row.int      "page_size" | ||||||
|             TimeZoneId          = TimeZoneId    (row.string "time_zone_id") |             TimeZoneId          = TimeZoneId    (row.string "time_zone_id") | ||||||
|             RequestSort         = RequestSort.fromCode     (row.string "request_sort") |             RequestSort         = RequestSort.Parse     (row.string "request_sort") | ||||||
|             DefaultEmailType    = EmailFormat.fromCode     (row.string "default_email_type") |             DefaultEmailType    = EmailFormat.Parse     (row.string "default_email_type") | ||||||
|             AsOfDateDisplay     = AsOfDateDisplay.fromCode (row.string "as_of_date_display") |             AsOfDateDisplay     = AsOfDateDisplay.Parse (row.string "as_of_date_display") | ||||||
|         } |         } | ||||||
|      |      | ||||||
|     /// Map a row to a Member instance |     /// Map a row to a Member instance | ||||||
| @ -47,7 +47,7 @@ module private Helpers = | |||||||
|             SmallGroupId = SmallGroupId     (row.uuid "small_group_id") |             SmallGroupId = SmallGroupId     (row.uuid "small_group_id") | ||||||
|             Name         = row.string       "member_name" |             Name         = row.string       "member_name" | ||||||
|             Email        = row.string       "email" |             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 |     /// Map a row to a Prayer Request instance | ||||||
| @ -60,8 +60,8 @@ module private Helpers = | |||||||
|             Requestor      = row.stringOrNone        "requestor" |             Requestor      = row.stringOrNone        "requestor" | ||||||
|             Text           = row.string              "request_text" |             Text           = row.string              "request_text" | ||||||
|             NotifyChaplain = row.bool                "notify_chaplain" |             NotifyChaplain = row.bool                "notify_chaplain" | ||||||
|             RequestType    = PrayerRequestType.fromCode (row.string "request_type") |             RequestType    = PrayerRequestType.Parse (row.string "request_type") | ||||||
|             Expiration     = Expiration.fromCode        (row.string "expiration") |             Expiration     = Expiration.Parse        (row.string "expiration") | ||||||
|         } |         } | ||||||
|      |      | ||||||
|     /// Map a row to a Small Group instance |     /// Map a row to a Small Group instance | ||||||
| @ -185,7 +185,7 @@ module Members = | |||||||
|                 "@groupId", Sql.uuid         mbr.SmallGroupId.Value |                 "@groupId", Sql.uuid         mbr.SmallGroupId.Value | ||||||
|                 "@name",    Sql.string       mbr.Name |                 "@name",    Sql.string       mbr.Name | ||||||
|                 "@email",   Sql.string       mbr.Email |                 "@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 |     /// Retrieve a small group member by its ID | ||||||
|     let tryById (memberId : MemberId) = |     let tryById (memberId : MemberId) = | ||||||
| @ -257,10 +257,10 @@ module PrayerRequests = | |||||||
|                          OR request_type = @expecting) |                          OR request_type = @expecting) | ||||||
|                     AND expiration <> @forced", |                     AND expiration <> @forced", | ||||||
|                 [   "@asOf",      Sql.parameter asOf |                 [   "@asOf",      Sql.parameter asOf | ||||||
|                     "@manual",    Sql.string    (Expiration.toCode Manual) |                     "@manual",    Sql.string    (string Manual) | ||||||
|                     "@longTerm",  Sql.string    (PrayerRequestType.toCode LongTermRequest) |                     "@longTerm",  Sql.string    (string LongTermRequest) | ||||||
|                     "@expecting", Sql.string    (PrayerRequestType.toCode Expecting) |                     "@expecting", Sql.string    (string Expecting) | ||||||
|                     "@forced",    Sql.string    (Expiration.toCode Forced) ] |                     "@forced",    Sql.string    (string Forced) ] | ||||||
|             else "", [] |             else "", [] | ||||||
|         Custom.list |         Custom.list | ||||||
|             $"SELECT * |             $"SELECT * | ||||||
| @ -287,15 +287,15 @@ module PrayerRequests = | |||||||
|                 notify_chaplain = EXCLUDED.notify_chaplain, |                 notify_chaplain = EXCLUDED.notify_chaplain, | ||||||
|                 expiration      = EXCLUDED.expiration" |                 expiration      = EXCLUDED.expiration" | ||||||
|             [   "@id",             Sql.uuid         req.Id.Value |             [   "@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 |                 "@userId",         Sql.uuid         req.UserId.Value | ||||||
|                 "@groupId",        Sql.uuid         req.SmallGroupId.Value |                 "@groupId",        Sql.uuid         req.SmallGroupId.Value | ||||||
|                 "@entered",        Sql.parameter    (NpgsqlParameter ("@entered", req.EnteredDate)) |                 "@entered",        Sql.parameter    (NpgsqlParameter("@entered", req.EnteredDate)) | ||||||
|                 "@updated",        Sql.parameter    (NpgsqlParameter ("@updated", req.UpdatedDate)) |                 "@updated",        Sql.parameter    (NpgsqlParameter("@updated", req.UpdatedDate)) | ||||||
|                 "@requestor",      Sql.stringOrNone req.Requestor |                 "@requestor",      Sql.stringOrNone req.Requestor | ||||||
|                 "@text",           Sql.string       req.Text |                 "@text",           Sql.string       req.Text | ||||||
|                 "@notifyChaplain", Sql.bool         req.NotifyChaplain |                 "@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 |     /// Search prayer requests for the given term | ||||||
|     let searchForGroup group searchTerm pageNbr = |     let searchForGroup group searchTerm pageNbr = | ||||||
| @ -320,9 +320,8 @@ module PrayerRequests = | |||||||
|                 [ "@updated", Sql.parameter (NpgsqlParameter ("@updated", req.UpdatedDate)) ] |                 [ "@updated", Sql.parameter (NpgsqlParameter ("@updated", req.UpdatedDate)) ] | ||||||
|             else "", [] |             else "", [] | ||||||
|         Custom.nonQuery $"UPDATE pt.prayer_request SET expiration = @expiration{sql} WHERE id = @id" |         Custom.nonQuery $"UPDATE pt.prayer_request SET expiration = @expiration{sql} WHERE id = @id" | ||||||
|                         ([  "@expiration", Sql.string (Expiration.toCode req.Expiration) |                         ([ "@expiration", Sql.string (string req.Expiration); "@id", Sql.uuid req.Id.Value ] | ||||||
|                             "@id",         Sql.uuid   req.Id.Value ] |                          |> List.append parameters) | ||||||
|                         |> List.append parameters) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// Functions to retrieve small group information | /// Functions to retrieve small group information | ||||||
| @ -455,13 +454,13 @@ module SmallGroups = | |||||||
|                 "@lineColor",           Sql.string pref.LineColor |                 "@lineColor",           Sql.string pref.LineColor | ||||||
|                 "@headingFontSize",     Sql.int    pref.HeadingFontSize |                 "@headingFontSize",     Sql.int    pref.HeadingFontSize | ||||||
|                 "@textFontSize",        Sql.int    pref.TextFontSize |                 "@textFontSize",        Sql.int    pref.TextFontSize | ||||||
|                 "@requestSort",         Sql.string (RequestSort.toCode pref.RequestSort) |                 "@requestSort",         Sql.string (string pref.RequestSort) | ||||||
|                 "@groupPassword",       Sql.string pref.GroupPassword |                 "@groupPassword",       Sql.string pref.GroupPassword | ||||||
|                 "@defaultEmailType",    Sql.string (EmailFormat.toCode pref.DefaultEmailType) |                 "@defaultEmailType",    Sql.string (string pref.DefaultEmailType) | ||||||
|                 "@isPublic",            Sql.bool   pref.IsPublic |                 "@isPublic",            Sql.bool   pref.IsPublic | ||||||
|                 "@timeZoneId",          Sql.string (TimeZoneId.toString pref.TimeZoneId) |                 "@timeZoneId",          Sql.string (TimeZoneId.toString pref.TimeZoneId) | ||||||
|                 "@pageSize",            Sql.int    pref.PageSize |                 "@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 |     /// Get a small group by its ID | ||||||
|     let tryById (groupId : SmallGroupId) = |     let tryById (groupId : SmallGroupId) = | ||||||
|  | |||||||
| @ -11,19 +11,20 @@ type AsOfDateDisplay = | |||||||
|     /// The as-of date should be displayed in the culture's long date format |     /// The as-of date should be displayed in the culture's long date format | ||||||
|     | LongDate |     | LongDate | ||||||
| 
 | 
 | ||||||
| /// Functions to support as-of date display options |     /// Convert this to a single-character code | ||||||
| module AsOfDateDisplay = |     override this.ToString() = | ||||||
|      |         match this with | ||||||
|     /// Convert to a DU case from a single-character string |         | NoDisplay -> "N" | ||||||
|     let fromCode code = |         | ShortDate -> "S" | ||||||
|  |         | LongDate -> "L" | ||||||
|  | 
 | ||||||
|  |     /// <summary>Create an <c>AsOfDateDisplay</c> from a single-character code</summary> | ||||||
|  |     static member Parse code = | ||||||
|         match code with |         match code with | ||||||
|         | "N" -> NoDisplay |         | "N" -> NoDisplay | ||||||
|         | "S" -> ShortDate |         | "S" -> ShortDate | ||||||
|         | "L" -> LongDate |         | "L" -> LongDate | ||||||
|         | _   -> invalidArg "code" $"Unknown code {code}" |         | _ -> invalidArg "code" $"Unknown code {code}" | ||||||
|      |  | ||||||
|     /// Convert this DU case to a single-character string |  | ||||||
|     let toCode = function NoDisplay -> "N" | ShortDate -> "S" | LongDate -> "L" |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// Acceptable e-mail formats | /// Acceptable e-mail formats | ||||||
| @ -33,18 +34,18 @@ type EmailFormat = | |||||||
|     /// Plain-text e-mail |     /// Plain-text e-mail | ||||||
|     | PlainTextFormat |     | PlainTextFormat | ||||||
| 
 | 
 | ||||||
| /// Functions to support e-mail formats |     /// Convert this to a single-character code | ||||||
| module EmailFormat = |     override this.ToString() = | ||||||
|      |         match this with | ||||||
|     /// Convert to a DU case from a single-character string |         | HtmlFormat -> "H" | ||||||
|     let fromCode code = |         | PlainTextFormat -> "P" | ||||||
|  | 
 | ||||||
|  |     /// <summary>Create an <c>EmailFormat</c> from a single-character code</summary> | ||||||
|  |     static member Parse code = | ||||||
|         match code with |         match code with | ||||||
|         | "H" -> HtmlFormat |         | "H" -> HtmlFormat | ||||||
|         | "P" -> PlainTextFormat |         | "P" -> PlainTextFormat | ||||||
|         | _   -> invalidArg "code" $"Unknown code {code}" |         | _ -> invalidArg "code" $"Unknown code {code}" | ||||||
|      |  | ||||||
|     /// Convert this DU case to a single-character string |  | ||||||
|     let toCode = function HtmlFormat -> "H" | PlainTextFormat -> "P" |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// Expiration for requests | /// Expiration for requests | ||||||
| @ -56,19 +57,20 @@ type Expiration = | |||||||
|     /// Force immediate expiration |     /// Force immediate expiration | ||||||
|     | Forced |     | Forced | ||||||
| 
 | 
 | ||||||
| /// Functions to support expirations |     /// Convert this to a single-character code | ||||||
| module Expiration = |     override this.ToString() = | ||||||
|      |         match this with | ||||||
|     /// Convert to a DU case from a single-character string |         | Automatic -> "A" | ||||||
|     let fromCode code = |         | Manual -> "M" | ||||||
|  |         | Forced -> "F" | ||||||
|  | 
 | ||||||
|  |     /// <summary>Create an <c>Expiration</c> from a single-character code</summary> | ||||||
|  |     static member Parse code = | ||||||
|         match code with |         match code with | ||||||
|         | "A" -> Automatic |         | "A" -> Automatic | ||||||
|         | "M" -> Manual |         | "M" -> Manual | ||||||
|         | "F" -> Forced |         | "F" -> Forced | ||||||
|         | _   -> invalidArg "code" $"Unknown code {code}" |         | _ -> invalidArg "code" $"Unknown code {code}" | ||||||
|      |  | ||||||
|     /// Convert this DU case to a single-character string |  | ||||||
|     let toCode = function Automatic -> "A" | Manual -> "M" | Forced -> "F" |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// Types of prayer requests | /// Types of prayer requests | ||||||
| @ -84,27 +86,24 @@ type PrayerRequestType = | |||||||
|     /// Announcements |     /// Announcements | ||||||
|     | Announcement |     | Announcement | ||||||
| 
 | 
 | ||||||
| /// Functions to support prayer request types |     /// Convert this to a single-character code | ||||||
| module PrayerRequestType = |     override this.ToString() = | ||||||
|      |         match this with | ||||||
|     /// Convert to a DU case from a single-character string |         | CurrentRequest -> "C" | ||||||
|     let fromCode code = |         | 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 |         match code with | ||||||
|         | "C" -> CurrentRequest |         | "C" -> CurrentRequest | ||||||
|         | "L" -> LongTermRequest |         | "L" -> LongTermRequest | ||||||
|         | "E" -> Expecting |         | "E" -> Expecting | ||||||
|         | "P" -> PraiseReport |         | "P" -> PraiseReport | ||||||
|         | "A" -> Announcement |         | "A" -> Announcement | ||||||
|         | _   -> invalidArg "code" $"Unknown code {code}" |         | _ -> 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" |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// How requests should be sorted | /// How requests should be sorted | ||||||
| @ -114,18 +113,18 @@ type RequestSort = | |||||||
|     /// Sort by requestor/subject, then by date |     /// Sort by requestor/subject, then by date | ||||||
|     | SortByRequestor |     | SortByRequestor | ||||||
| 
 | 
 | ||||||
| /// Functions to support request sorts |     /// Convert this to a single-character code | ||||||
| module RequestSort = |     override this.ToString() = | ||||||
|      |         match this with | ||||||
|     /// Convert to a DU case from a single-character string |         | SortByDate -> "D" | ||||||
|     let fromCode code = |         | SortByRequestor -> "R" | ||||||
|  | 
 | ||||||
|  |     /// <summary>Create a <c>RequestSort</c> from a single-character code</summary> | ||||||
|  |     static member Parse code = | ||||||
|         match code with |         match code with | ||||||
|         | "D" -> SortByDate |         | "D" -> SortByDate | ||||||
|         | "R" -> SortByRequestor |         | "R" -> SortByRequestor | ||||||
|         | _   -> invalidArg "code" $"Unknown code {code}" |         | _ -> invalidArg "code" $"Unknown code {code}" | ||||||
|      |  | ||||||
|     /// Convert this DU case to a single-character string |  | ||||||
|     let toCode = function SortByDate -> "D" | SortByRequestor -> "R" |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| open System | open System | ||||||
| @ -133,33 +132,45 @@ open System | |||||||
| /// PK type for the Church entity | /// PK type for the Church entity | ||||||
| type ChurchId = | type ChurchId = | ||||||
|     | ChurchId of Guid |     | ChurchId of Guid | ||||||
| with | 
 | ||||||
|     /// The GUID value of the church ID |     /// 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 | /// PK type for the Member entity | ||||||
| type MemberId = | type MemberId = | ||||||
|     | MemberId of Guid |     | MemberId of Guid | ||||||
| with | 
 | ||||||
|     /// The GUID value of the member ID |     /// 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 | /// PK type for the PrayerRequest entity | ||||||
| type PrayerRequestId = | type PrayerRequestId = | ||||||
|     | PrayerRequestId of Guid |     | PrayerRequestId of Guid | ||||||
| with | 
 | ||||||
|     /// The GUID value of the prayer request ID |     /// 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 | /// PK type for the SmallGroup entity | ||||||
| type SmallGroupId = | type SmallGroupId = | ||||||
|     | SmallGroupId of Guid |     | SmallGroupId of Guid | ||||||
| with | 
 | ||||||
|     /// The GUID value of the small group ID |     /// 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 | /// PK type for the TimeZone entity | ||||||
| @ -167,51 +178,58 @@ type TimeZoneId = TimeZoneId of string | |||||||
| 
 | 
 | ||||||
| /// Functions to support time zone IDs | /// Functions to support time zone IDs | ||||||
| module TimeZoneId = | module TimeZoneId = | ||||||
|      | 
 | ||||||
|     /// Convert a time zone ID to its string value |     /// 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 | /// PK type for the User entity | ||||||
| type UserId = | type UserId = | ||||||
|     | UserId of Guid |     | UserId of Guid | ||||||
| with | 
 | ||||||
|     /// The GUID value of the user ID |     /// 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 --*) | (*-- SPECIFIC VIEW TYPES --*) | ||||||
| 
 | 
 | ||||||
| /// Statistics for churches | /// Statistics for churches | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type ChurchStats = | 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 |         /// The number of prayer requests in the church | ||||||
|         PrayerRequests : int |         PrayerRequests: int | ||||||
|          | 
 | ||||||
|         /// The number of users who can access small groups in the church |         /// 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 | /// Information needed to display the public/protected request list and small group maintenance pages | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type SmallGroupInfo = | type SmallGroupInfo = | ||||||
|     {   /// The ID of the small group |     { | ||||||
|         Id : string |         /// The ID of the small group | ||||||
|          |         Id: string | ||||||
|  | 
 | ||||||
|         /// The name of the small group |         /// The name of the small group | ||||||
|         Name : string |         Name: string | ||||||
|          | 
 | ||||||
|         /// The name of the church to which the small group belongs |         /// 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 |         /// The ID of the time zone for the small group | ||||||
|         TimeZoneId : TimeZoneId |         TimeZoneId: TimeZoneId | ||||||
|          | 
 | ||||||
|         /// Whether the small group has a publicly-available request list |         /// Whether the small group has a publicly-available request list | ||||||
|         IsPublic : bool |         IsPublic: bool | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| (*-- ENTITIES --*) | (*-- ENTITIES --*) | ||||||
| @ -221,195 +239,196 @@ open NodaTime | |||||||
| /// This represents a church | /// This represents a church | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type Church = | type Church = | ||||||
|     {   /// The ID of this church |     { | ||||||
|         Id : ChurchId |         /// The ID of this church | ||||||
|          |         Id: ChurchId | ||||||
|  | 
 | ||||||
|         /// The name of the church |         /// The name of the church | ||||||
|         Name : string |         Name: string | ||||||
|          | 
 | ||||||
|         /// The city where the church is |         /// The city where the church is | ||||||
|         City : string |         City: string | ||||||
|          | 
 | ||||||
|         /// The 2-letter state or province code for the church's location |         /// 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? |         /// Does this church have an active interface with Virtual Prayer Space? | ||||||
|         HasVpsInterface : bool |         HasVpsInterface: bool | ||||||
|          | 
 | ||||||
|         /// The address for the interface |         /// The address for the interface | ||||||
|         InterfaceAddress : string option |         InterfaceAddress: string option | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| /// Functions to support churches | /// Functions to support churches | ||||||
| module Church = | module Church = | ||||||
|      | 
 | ||||||
|     /// An empty church |     /// An empty church | ||||||
|     // aww... how sad :( |     // aww... how sad :( | ||||||
|     let empty = |     let empty = | ||||||
|         {   Id               = ChurchId Guid.Empty |         { Id = ChurchId Guid.Empty | ||||||
|             Name             = "" |           Name = "" | ||||||
|             City             = "" |           City = "" | ||||||
|             State            = "" |           State = "" | ||||||
|             HasVpsInterface  = false |           HasVpsInterface = false | ||||||
|             InterfaceAddress = None |           InterfaceAddress = None } | ||||||
|         } | 
 | ||||||
|      |  | ||||||
| 
 | 
 | ||||||
| /// Preferences for the form and format of the prayer request list | /// Preferences for the form and format of the prayer request list | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type ListPreferences = | 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 |         /// The days after which regular requests expire | ||||||
|         DaysToExpire : int |         DaysToExpire: int | ||||||
|          | 
 | ||||||
|         /// The number of days a new or updated request is considered new |         /// 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 |         /// 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 |         /// The name from which e-mails are sent | ||||||
|         EmailFromName : string |         EmailFromName: string | ||||||
|          | 
 | ||||||
|         /// The e-mail address from which e-mails are sent |         /// 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 |         /// The fonts to use in generating the list of prayer requests | ||||||
|         Fonts : string |         Fonts: string | ||||||
|          | 
 | ||||||
|         /// The color for the prayer request list headings |         /// The color for the prayer request list headings | ||||||
|         HeadingColor : string |         HeadingColor: string | ||||||
|          | 
 | ||||||
|         /// The color for the lines offsetting the prayer request list headings |         /// 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 |         /// 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 |         /// The font size for the text on the prayer request list | ||||||
|         TextFontSize : int |         TextFontSize: int | ||||||
|          | 
 | ||||||
|         /// The order in which the prayer requests are sorted |         /// The order in which the prayer requests are sorted | ||||||
|         RequestSort : RequestSort |         RequestSort: RequestSort | ||||||
|          | 
 | ||||||
|         /// The password used for "small group login" (view-only request list) |         /// The password used for "small group login" (view-only request list) | ||||||
|         GroupPassword : string |         GroupPassword: string | ||||||
|          | 
 | ||||||
|         /// The default e-mail type for this class |         /// The default e-mail type for this class | ||||||
|         DefaultEmailType : EmailFormat |         DefaultEmailType: EmailFormat | ||||||
|          | 
 | ||||||
|         /// Whether this class makes its request list public |         /// Whether this class makes its request list public | ||||||
|         IsPublic : bool |         IsPublic: bool | ||||||
|          | 
 | ||||||
|         /// The time zone which this class uses (use tzdata names) |         /// The time zone which this class uses (use tzdata names) | ||||||
|         TimeZoneId : TimeZoneId |         TimeZoneId: TimeZoneId | ||||||
|          | 
 | ||||||
|         /// The number of requests displayed per page |         /// The number of requests displayed per page | ||||||
|         PageSize : int |         PageSize: int | ||||||
|          | 
 | ||||||
|         /// How the as-of date should be automatically displayed |         /// 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) |     /// The list of fonts to use when displaying request lists (converts "native" to native font stack) | ||||||
|     member this.FontStack = |     member this.FontStack = | ||||||
|         if this.Fonts = "native" then |         if this.Fonts = "native" then | ||||||
|             """system-ui,-apple-system,"Segoe UI",Roboto,Ubuntu,"Liberation Sans",Cantarell,"Helvetica Neue",sans-serif""" |             """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 | /// Functions to support list preferences | ||||||
| module ListPreferences = | module ListPreferences = | ||||||
|      | 
 | ||||||
|     /// A set of preferences with their default values |     /// A set of preferences with their default values | ||||||
|     let empty = |     let empty = | ||||||
|         {   SmallGroupId        = SmallGroupId Guid.Empty |         { SmallGroupId = SmallGroupId Guid.Empty | ||||||
|             DaysToExpire        = 14 |           DaysToExpire = 14 | ||||||
|             DaysToKeepNew       = 7 |           DaysToKeepNew = 7 | ||||||
|             LongTermUpdateWeeks = 4 |           LongTermUpdateWeeks = 4 | ||||||
|             EmailFromName       = "PrayerTracker" |           EmailFromName = "PrayerTracker" | ||||||
|             EmailFromAddress    = "prayer@bitbadger.solutions" |           EmailFromAddress = "prayer@bitbadger.solutions" | ||||||
|             Fonts               = "native" |           Fonts = "native" | ||||||
|             HeadingColor        = "maroon" |           HeadingColor = "maroon" | ||||||
|             LineColor           = "navy" |           LineColor = "navy" | ||||||
|             HeadingFontSize     = 16 |           HeadingFontSize = 16 | ||||||
|             TextFontSize        = 12 |           TextFontSize = 12 | ||||||
|             RequestSort         = SortByDate |           RequestSort = SortByDate | ||||||
|             GroupPassword       = "" |           GroupPassword = "" | ||||||
|             DefaultEmailType    = HtmlFormat |           DefaultEmailType = HtmlFormat | ||||||
|             IsPublic            = false |           IsPublic = false | ||||||
|             TimeZoneId          = TimeZoneId "America/Denver" |           TimeZoneId = TimeZoneId "America/Denver" | ||||||
|             PageSize            = 100 |           PageSize = 100 | ||||||
|             AsOfDateDisplay     = NoDisplay |           AsOfDateDisplay = NoDisplay } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// A member of a small group | /// A member of a small group | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type Member = | 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 |         /// The Id of the small group to which this member belongs | ||||||
|         SmallGroupId : SmallGroupId |         SmallGroupId: SmallGroupId | ||||||
|          | 
 | ||||||
|         /// The name of the member |         /// The name of the member | ||||||
|         Name : string |         Name: string | ||||||
|          | 
 | ||||||
|         /// The e-mail address for the member |         /// The e-mail address for the member | ||||||
|         Email : string |         Email: string | ||||||
|          | 
 | ||||||
|         /// The type of e-mail preferred by this member |         /// The type of e-mail preferred by this member | ||||||
|         Format : EmailFormat option |         Format: EmailFormat option | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| /// Functions to support small group members | /// Functions to support small group members | ||||||
| module Member = | module Member = | ||||||
|      | 
 | ||||||
|     /// An empty member |     /// An empty member | ||||||
|     let empty = |     let empty = | ||||||
|         {   Id           = MemberId Guid.Empty |         { Id = MemberId Guid.Empty | ||||||
|             SmallGroupId = SmallGroupId Guid.Empty |           SmallGroupId = SmallGroupId Guid.Empty | ||||||
|             Name         = "" |           Name = "" | ||||||
|             Email        = "" |           Email = "" | ||||||
|             Format       = None |           Format = None } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// This represents a single prayer request | /// This represents a single prayer request | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type PrayerRequest = | type PrayerRequest = | ||||||
|     {   /// The ID of this request |     { | ||||||
|         Id : PrayerRequestId |         /// The ID of this request | ||||||
|          |         Id: PrayerRequestId | ||||||
|  | 
 | ||||||
|         /// The type of the request |         /// The type of the request | ||||||
|         RequestType : PrayerRequestType |         RequestType: PrayerRequestType | ||||||
|          | 
 | ||||||
|         /// The ID of the user who entered the request |         /// The ID of the user who entered the request | ||||||
|         UserId : UserId |         UserId: UserId | ||||||
|          | 
 | ||||||
|         /// The small group to which this request belongs |         /// The small group to which this request belongs | ||||||
|         SmallGroupId : SmallGroupId |         SmallGroupId: SmallGroupId | ||||||
|          | 
 | ||||||
|         /// The date/time on which this request was entered |         /// The date/time on which this request was entered | ||||||
|         EnteredDate : Instant |         EnteredDate: Instant | ||||||
|          | 
 | ||||||
|         /// The date/time this request was last updated |         /// The date/time this request was last updated | ||||||
|         UpdatedDate : Instant |         UpdatedDate: Instant | ||||||
|          | 
 | ||||||
|         /// The name of the requestor or subject, or title of announcement |         /// The name of the requestor or subject, or title of announcement | ||||||
|         Requestor : string option |         Requestor: string option | ||||||
|          | 
 | ||||||
|         /// The text of the request |         /// The text of the request | ||||||
|         Text : string |         Text: string | ||||||
|          | 
 | ||||||
|         /// Whether the chaplain should be notified for this request |         /// Whether the chaplain should be notified for this request | ||||||
|         NotifyChaplain : bool |         NotifyChaplain: bool | ||||||
|          | 
 | ||||||
|         /// Is this request expired? |         /// Is this request expired? | ||||||
|         Expiration : Expiration |         Expiration: Expiration | ||||||
|     } |     } | ||||||
| // functions are below small group functions | // functions are below small group functions | ||||||
| 
 | 
 | ||||||
| @ -417,141 +436,147 @@ type PrayerRequest = | |||||||
| /// This represents a small group (Sunday School class, Bible study group, etc.) | /// This represents a small group (Sunday School class, Bible study group, etc.) | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type SmallGroup = | 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 |         /// The church to which this group belongs | ||||||
|         ChurchId : ChurchId |         ChurchId: ChurchId | ||||||
|          | 
 | ||||||
|         /// The name of the group |         /// The name of the group | ||||||
|         Name : string |         Name: string | ||||||
|          | 
 | ||||||
|         /// The preferences for the request list |         /// The preferences for the request list | ||||||
|         Preferences : ListPreferences |         Preferences: ListPreferences | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| /// Functions to support small groups | /// Functions to support small groups | ||||||
| module SmallGroup = | module SmallGroup = | ||||||
|      | 
 | ||||||
|     /// An empty small group |     /// An empty small group | ||||||
|     let empty = |     let empty = | ||||||
|         {   Id          = SmallGroupId Guid.Empty |         { Id = SmallGroupId Guid.Empty | ||||||
|             ChurchId    = ChurchId Guid.Empty |           ChurchId = ChurchId Guid.Empty | ||||||
|             Name        = ""  |           Name = "" | ||||||
|             Preferences = ListPreferences.empty |           Preferences = ListPreferences.empty } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|     /// The DateTimeZone for the time zone ID for this small group |     /// The DateTimeZone for the time zone ID for this small group | ||||||
|     let timeZone group = |     let timeZone group = | ||||||
|         let tzId = TimeZoneId.toString group.Preferences.TimeZoneId |         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 |     /// Get the local date/time for this group | ||||||
|     let localTimeNow (clock : IClock) group = |     let localTimeNow (clock: IClock) group = | ||||||
|         if isNull clock then nullArg (nameof clock) |         if isNull clock then | ||||||
|  |             nullArg (nameof clock) | ||||||
|  | 
 | ||||||
|         clock.GetCurrentInstant().InZone(timeZone group).LocalDateTime |         clock.GetCurrentInstant().InZone(timeZone group).LocalDateTime | ||||||
| 
 | 
 | ||||||
|     /// Get the local date for this group |     /// Get the local date for this group | ||||||
|     let localDateNow clock group = |     let localDateNow clock group = (localTimeNow clock group).Date | ||||||
|         (localTimeNow clock group).Date |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// Functions to support prayer requests | /// Functions to support prayer requests | ||||||
| module PrayerRequest = | module PrayerRequest = | ||||||
|      | 
 | ||||||
|     /// An empty request |     /// An empty request | ||||||
|     let empty = |     let empty = | ||||||
|         {   Id             = PrayerRequestId Guid.Empty |         { Id = PrayerRequestId Guid.Empty | ||||||
|             RequestType    = CurrentRequest |           RequestType = CurrentRequest | ||||||
|             UserId         = UserId Guid.Empty |           UserId = UserId Guid.Empty | ||||||
|             SmallGroupId   = SmallGroupId Guid.Empty |           SmallGroupId = SmallGroupId Guid.Empty | ||||||
|             EnteredDate    = Instant.MinValue |           EnteredDate = Instant.MinValue | ||||||
|             UpdatedDate    = Instant.MinValue |           UpdatedDate = Instant.MinValue | ||||||
|             Requestor      = None |           Requestor = None | ||||||
|             Text           = ""  |           Text = "" | ||||||
|             NotifyChaplain = false |           NotifyChaplain = false | ||||||
|             Expiration     = Automatic |           Expiration = Automatic } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|     /// Is this request expired? |     /// Is this request expired? | ||||||
|     let isExpired (asOf : LocalDate) group req = |     let isExpired (asOf: LocalDate) group req = | ||||||
|         match req.Expiration, req.RequestType with |         match req.Expiration, req.RequestType with | ||||||
|         | Forced, _ -> true |         | Forced, _ -> true | ||||||
|         | Manual, _  |         | Manual, _ | ||||||
|         | Automatic, LongTermRequest |         | Automatic, LongTermRequest | ||||||
|         | Automatic, Expecting  -> false |         | Automatic, Expecting -> false | ||||||
|         | Automatic, _ -> |         | Automatic, _ -> | ||||||
|             // Automatic expiration |             // Automatic expiration | ||||||
|             Period.Between(req.UpdatedDate.InZone(SmallGroup.timeZone group).Date, asOf, PeriodUnits.Days).Days |             Period | ||||||
|                 >= group.Preferences.DaysToExpire |                 .Between(req.UpdatedDate.InZone(SmallGroup.timeZone group).Date, asOf, PeriodUnits.Days) | ||||||
|  |                 .Days | ||||||
|  |             >= group.Preferences.DaysToExpire | ||||||
| 
 | 
 | ||||||
|     /// Is an update required for this long-term request? |     /// Is an update required for this long-term request? | ||||||
|     let updateRequired asOf group req = |     let updateRequired asOf group req = | ||||||
|         if isExpired asOf group req then false |         if isExpired asOf group req then | ||||||
|         else asOf.PlusWeeks -group.Preferences.LongTermUpdateWeeks |             false | ||||||
|                 >= req.UpdatedDate.InZone(SmallGroup.timeZone group).Date |         else | ||||||
|  |             asOf.PlusWeeks -group.Preferences.LongTermUpdateWeeks | ||||||
|  |             >= req.UpdatedDate.InZone(SmallGroup.timeZone group).Date | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// This represents a user of PrayerTracker | /// This represents a user of PrayerTracker | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type User = | type User = | ||||||
|     {   /// The ID of this user |     { | ||||||
|         Id : UserId |         /// The ID of this user | ||||||
|          |         Id: UserId | ||||||
|  | 
 | ||||||
|         /// The first name of this user |         /// The first name of this user | ||||||
|         FirstName : string |         FirstName: string | ||||||
|          | 
 | ||||||
|         /// The last name of this user |         /// The last name of this user | ||||||
|         LastName : string |         LastName: string | ||||||
|          | 
 | ||||||
|         /// The e-mail address of the user |         /// The e-mail address of the user | ||||||
|         Email : string |         Email: string | ||||||
|          | 
 | ||||||
|         /// Whether this user is a PrayerTracker system administrator |         /// Whether this user is a PrayerTracker system administrator | ||||||
|         IsAdmin : bool |         IsAdmin: bool | ||||||
|          | 
 | ||||||
|         /// The user's hashed password |         /// 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) |         /// 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 |     /// The full name of the user | ||||||
|     member this.Name = |     member this.Name = $"{this.FirstName} {this.LastName}" | ||||||
|         $"{this.FirstName} {this.LastName}" |  | ||||||
| 
 | 
 | ||||||
| /// Functions to support users | /// Functions to support users | ||||||
| module User = | module User = | ||||||
|      | 
 | ||||||
|     /// An empty user |     /// An empty user | ||||||
|     let empty = |     let empty = | ||||||
|         {   Id           = UserId Guid.Empty |         { Id = UserId Guid.Empty | ||||||
|             FirstName    = "" |           FirstName = "" | ||||||
|             LastName     = "" |           LastName = "" | ||||||
|             Email        = "" |           Email = "" | ||||||
|             IsAdmin      = false |           IsAdmin = false | ||||||
|             PasswordHash = "" |           PasswordHash = "" | ||||||
|             LastSeen     = None |           LastSeen = None } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /// Cross-reference between user and small group | /// Cross-reference between user and small group | ||||||
| [<NoComparison; NoEquality>] | [<NoComparison; NoEquality>] | ||||||
| type UserSmallGroup = | 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 |         /// The Id of the small group to which the user has access | ||||||
|         SmallGroupId : SmallGroupId |         SmallGroupId: SmallGroupId | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| /// Functions to support user/small group cross-reference | /// Functions to support user/small group cross-reference | ||||||
| module UserSmallGroup = | module UserSmallGroup = | ||||||
|      | 
 | ||||||
|     /// An empty user/small group xref |     /// An empty user/small group xref | ||||||
|     let empty = |     let empty = | ||||||
|         {   UserId       = UserId Guid.Empty |         { UserId = UserId Guid.Empty | ||||||
|             SmallGroupId = SmallGroupId Guid.Empty |           SmallGroupId = SmallGroupId Guid.Empty } | ||||||
|         } |  | ||||||
|  | |||||||
| @ -8,28 +8,32 @@ open System | |||||||
| [<Tests>] | [<Tests>] | ||||||
| let asOfDateDisplayTests = | let asOfDateDisplayTests = | ||||||
|     testList "AsOfDateDisplay" [ |     testList "AsOfDateDisplay" [ | ||||||
|         test "NoDisplay code is correct" { |         testList "ToString" [ | ||||||
|             Expect.equal (AsOfDateDisplay.toCode NoDisplay) "N" "The code for NoDisplay should have been \"N\"" |             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 (AsOfDateDisplay.toCode ShortDate) "S" "The code for ShortDate should have been \"S\"" |             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 (AsOfDateDisplay.toCode LongDate) "L" "The code for LongDate should have been \"N\"" |             test "LongDate code is correct" { | ||||||
|         } |                 Expect.equal (string 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" |         ] | ||||||
|         } |         testList "Parse" [ | ||||||
|         test "fromCode S should return ShortDate" { |             test "N should return NoDisplay" { | ||||||
|             Expect.equal (AsOfDateDisplay.fromCode "S") ShortDate "\"S\" should have been converted to ShortDate" |                 Expect.equal (AsOfDateDisplay.Parse "N") NoDisplay "\"N\" should have been parsed to NoDisplay" | ||||||
|         } |             } | ||||||
|         test "fromCode L should return LongDate" { |             test "S should return ShortDate" { | ||||||
|             Expect.equal (AsOfDateDisplay.fromCode "L") LongDate "\"L\" should have been converted to LongDate" |                 Expect.equal (AsOfDateDisplay.Parse "S") ShortDate "\"S\" should have been parsed to ShortDate" | ||||||
|         } |             } | ||||||
|         test "fromCode X should raise" { |             test "L should return LongDate" { | ||||||
|             Expect.throws (fun () -> AsOfDateDisplay.fromCode "X" |> ignore) |                 Expect.equal (AsOfDateDisplay.Parse "L") LongDate "\"L\" should have been parsed to LongDate" | ||||||
|                 "An unknown code should have raised an exception" |             } | ||||||
|         } |             test "X should raise" { | ||||||
|  |                 Expect.throws (fun () -> AsOfDateDisplay.Parse "X" |> ignore) | ||||||
|  |                     "An unknown code should have raised an exception" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
| [<Tests>] | [<Tests>] | ||||||
| @ -49,50 +53,58 @@ let churchTests = | |||||||
| [<Tests>] | [<Tests>] | ||||||
| let emailFormatTests = | let emailFormatTests = | ||||||
|     testList "EmailFormat" [ |     testList "EmailFormat" [ | ||||||
|         test "HtmlFormat code is correct" { |         testList "ToString" [ | ||||||
|             Expect.equal (EmailFormat.toCode HtmlFormat) "H" "The code for HtmlFormat should have been \"H\"" |             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 (EmailFormat.toCode PlainTextFormat) "P" "The code for PlainTextFormat should have been \"P\"" |             test "PlainTextFormat code is correct" { | ||||||
|         } |                 Expect.equal (string 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" |         ] | ||||||
|         } |         testList "Parse" [ | ||||||
|         test "fromCode P should return ShortDate" { |             test "H should return HtmlFormat" { | ||||||
|             Expect.equal (EmailFormat.fromCode "P") PlainTextFormat |                 Expect.equal (EmailFormat.Parse "H") HtmlFormat "\"H\" should have been converted to HtmlFormat" | ||||||
|                 "\"P\" should have been converted to PlainTextFormat" |             } | ||||||
|         } |             test "P should return ShortDate" { | ||||||
|         test "fromCode Z should raise" { |                 Expect.equal (EmailFormat.Parse "P") PlainTextFormat | ||||||
|             Expect.throws (fun () -> EmailFormat.fromCode "Z" |> ignore) |                     "\"P\" should have been converted to PlainTextFormat" | ||||||
|                 "An unknown code should have raised an exception" |             } | ||||||
|         } |             test "Z should raise" { | ||||||
|  |                 Expect.throws (fun () -> EmailFormat.Parse "Z" |> ignore) | ||||||
|  |                     "An unknown code should have raised an exception" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
| [<Tests>] | [<Tests>] | ||||||
| let expirationTests = | let expirationTests = | ||||||
|     testList "Expiration" [ |     testList "Expiration" [ | ||||||
|         test "Automatic code is correct" { |         testList "ToString" [ | ||||||
|             Expect.equal (Expiration.toCode Automatic) "A" "The code for Automatic should have been \"A\"" |             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 (Expiration.toCode Manual) "M" "The code for Manual should have been \"M\"" |             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 (Expiration.toCode Forced) "F" "The code for Forced should have been \"F\"" |             test "Forced code is correct" { | ||||||
|         } |                 Expect.equal (string 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" |         ] | ||||||
|         } |         testList "Parse" [ | ||||||
|         test "fromCode M should return Manual" { |             test "A should return Automatic" { | ||||||
|             Expect.equal (Expiration.fromCode "M") Manual "\"M\" should have been converted to Manual" |                 Expect.equal (Expiration.Parse "A") Automatic "\"A\" should have been converted to Automatic" | ||||||
|         } |             } | ||||||
|         test "fromCode F should return Forced" { |             test "M should return Manual" { | ||||||
|             Expect.equal (Expiration.fromCode "F") Forced "\"F\" should have been converted to Forced" |                 Expect.equal (Expiration.Parse "M") Manual "\"M\" should have been converted to Manual" | ||||||
|         } |             } | ||||||
|         test "fromCode V should raise" { |             test "F should return Forced" { | ||||||
|             Expect.throws (fun () -> Expiration.fromCode "V" |> ignore) |                 Expect.equal (Expiration.Parse "F") Forced "\"F\" should have been converted to Forced" | ||||||
|                 "An unknown code should have raised an exception" |             } | ||||||
|         } |             test "fromCode V should raise" { | ||||||
|  |                 Expect.throws (fun () -> Expiration.Parse "V" |> ignore) | ||||||
|  |                     "An unknown code should have raised an exception" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
| [<Tests>] | [<Tests>] | ||||||
| @ -223,68 +235,74 @@ let prayerRequestTests = | |||||||
| [<Tests>] | [<Tests>] | ||||||
| let prayerRequestTypeTests = | let prayerRequestTypeTests = | ||||||
|     testList "PrayerRequestType" [ |     testList "PrayerRequestType" [ | ||||||
|         test "CurrentRequest code is correct" { |         testList "ToString" [ | ||||||
|             Expect.equal (PrayerRequestType.toCode CurrentRequest) "C" |             test "CurrentRequest code is correct" { | ||||||
|                 "The code for CurrentRequest should have been \"C\"" |                 Expect.equal (string CurrentRequest) "C" "The code for CurrentRequest should have been \"C\"" | ||||||
|         } |             } | ||||||
|         test "LongTermRequest code is correct" { |             test "LongTermRequest code is correct" { | ||||||
|             Expect.equal (PrayerRequestType.toCode LongTermRequest) "L" |                 Expect.equal (string LongTermRequest) "L" "The code for LongTermRequest should have been \"L\"" | ||||||
|                 "The code for LongTermRequest should have been \"L\"" |             } | ||||||
|         } |             test "PraiseReport code is correct" { | ||||||
|         test "PraiseReport code is correct" { |                 Expect.equal (string PraiseReport) "P" "The code for PraiseReport should have been \"P\"" | ||||||
|             Expect.equal (PrayerRequestType.toCode PraiseReport) "P" "The code for PraiseReport should have been \"P\"" |             } | ||||||
|         } |             test "Expecting code is correct" { | ||||||
|         test "Expecting code is correct" { |                 Expect.equal (string Expecting) "E" "The code for Expecting should have been \"E\"" | ||||||
|             Expect.equal (PrayerRequestType.toCode Expecting) "E" "The code for Expecting should have been \"E\"" |             } | ||||||
|         } |             test "Announcement code is correct" { | ||||||
|         test "Announcement code is correct" { |                 Expect.equal (string Announcement) "A" "The code for Announcement should have been \"A\"" | ||||||
|             Expect.equal (PrayerRequestType.toCode Announcement) "A" "The code for Announcement should have been \"A\"" |             } | ||||||
|         } |         ] | ||||||
|         test "fromCode C should return CurrentRequest" { |         testList "Parse" [ | ||||||
|             Expect.equal (PrayerRequestType.fromCode "C") CurrentRequest |             test "C should return CurrentRequest" { | ||||||
|                 "\"C\" should have been converted to CurrentRequest" |                 Expect.equal (PrayerRequestType.Parse "C") CurrentRequest | ||||||
|         } |                     "\"C\" should have been converted to CurrentRequest" | ||||||
|         test "fromCode L should return LongTermRequest" { |             } | ||||||
|             Expect.equal (PrayerRequestType.fromCode "L") LongTermRequest |             test "L should return LongTermRequest" { | ||||||
|                 "\"L\" should have been converted to LongTermRequest" |                 Expect.equal (PrayerRequestType.Parse "L") LongTermRequest | ||||||
|         } |                     "\"L\" should have been converted to LongTermRequest" | ||||||
|         test "fromCode P should return PraiseReport" { |             } | ||||||
|             Expect.equal (PrayerRequestType.fromCode "P") PraiseReport |             test "P should return PraiseReport" { | ||||||
|                 "\"P\" should have been converted to PraiseReport" |                 Expect.equal (PrayerRequestType.Parse "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 "E should return Expecting" { | ||||||
|         } |                 Expect.equal (PrayerRequestType.Parse "E") Expecting "\"E\" should have been converted to Expecting" | ||||||
|         test "fromCode A should return Announcement" { |             } | ||||||
|             Expect.equal (PrayerRequestType.fromCode "A") Announcement |             test "A should return Announcement" { | ||||||
|                 "\"A\" should have been converted to Announcement" |                 Expect.equal (PrayerRequestType.Parse "A") Announcement | ||||||
|         } |                     "\"A\" should have been converted to Announcement" | ||||||
|         test "fromCode R should raise" { |             } | ||||||
|             Expect.throws (fun () -> PrayerRequestType.fromCode "R" |> ignore) |             test "R should raise" { | ||||||
|                 "An unknown code should have raised an exception" |                 Expect.throws (fun () -> PrayerRequestType.Parse "R" |> ignore) | ||||||
|         } |                     "An unknown code should have raised an exception" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
| [<Tests>] | [<Tests>] | ||||||
| let requestSortTests = | let requestSortTests = | ||||||
|     testList "RequestSort" [ |     testList "RequestSort" [ | ||||||
|         test "SortByDate code is correct" { |         testList "ToString" [ | ||||||
|             Expect.equal (RequestSort.toCode SortByDate) "D" "The code for SortByDate should have been \"D\"" |             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 (RequestSort.toCode SortByRequestor) "R" "The code for SortByRequestor should have been \"R\"" |             test "SortByRequestor code is correct" { | ||||||
|         } |                 Expect.equal (string 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" |         ] | ||||||
|         } |         testList "Parse" [ | ||||||
|         test "fromCode R should return SortByRequestor" { |             test "D should return SortByDate" { | ||||||
|             Expect.equal (RequestSort.fromCode "R") SortByRequestor |                 Expect.equal (RequestSort.Parse "D") SortByDate "\"D\" should have been converted to SortByDate" | ||||||
|                 "\"R\" should have been converted to SortByRequestor" |             } | ||||||
|         } |             test "R should return SortByRequestor" { | ||||||
|         test "fromCode Q should raise" { |                 Expect.equal (RequestSort.Parse "R") SortByRequestor | ||||||
|             Expect.throws (fun () -> RequestSort.fromCode "Q" |> ignore) |                     "\"R\" should have been converted to SortByRequestor" | ||||||
|                 "An unknown code should have raised an exception" |             } | ||||||
|         } |             test "Q should raise" { | ||||||
|  |                 Expect.throws (fun () -> RequestSort.Parse "Q" |> ignore) | ||||||
|  |                     "An unknown code should have raised an exception" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
| [<Tests>] | [<Tests>] | ||||||
|  | |||||||
| @ -22,12 +22,9 @@ module ReferenceListTests = | |||||||
|             test "has all three options listed" { |             test "has all three options listed" { | ||||||
|                 let asOf = ReferenceList.asOfDateList _s |                 let asOf = ReferenceList.asOfDateList _s | ||||||
|                 Expect.hasCountOf asOf 3u countAll "There should have been 3 as-of choices returned" |                 Expect.hasCountOf asOf 3u countAll "There should have been 3 as-of choices returned" | ||||||
|                 Expect.exists asOf (fun (x, _) -> x = AsOfDateDisplay.toCode NoDisplay) |                 Expect.exists asOf (fun (x, _) -> x = string NoDisplay) "The option for no display was not found" | ||||||
|                     "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 = AsOfDateDisplay.toCode ShortDate) |                 Expect.exists asOf (fun (x, _) -> x = string LongDate) "The option for a full date was not found" | ||||||
|                     "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" |  | ||||||
|             } |             } | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
| @ -41,9 +38,9 @@ module ReferenceListTests = | |||||||
|                 Expect.equal (fst top) "" "The default option should have been blank" |                 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" |                 Expect.equal (snd top).Value "Group Default (HTML Format)" "The default option label was incorrect" | ||||||
|                 let nxt = typs |> Seq.skip 1 |> Seq.head |                 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 |                 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" { |             test "excludes immediate expiration if not required" { | ||||||
|                 let exps = ReferenceList.expirationList _s false |                 let exps = ReferenceList.expirationList _s false | ||||||
|                 Expect.hasCountOf exps 2u countAll "There should have been 2 expiration types returned" |                 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" |                     "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" |                     "The option for manual expiration was not found" | ||||||
|             } |             } | ||||||
|             test "includes immediate expiration if required" { |             test "includes immediate expiration if required" { | ||||||
|                 let exps = ReferenceList.expirationList _s true |                 let exps = ReferenceList.expirationList _s true | ||||||
|                 Expect.hasCountOf exps 3u countAll "There should have been 3 expiration types returned" |                 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" |                     "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" |                     "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" |                     "The option for immediate expiration was not found" | ||||||
|             } |             } | ||||||
|         ] |         ] | ||||||
| @ -240,7 +237,7 @@ let editMemberTests = | |||||||
|         } |         } | ||||||
|         test "fromMember populates with specific format" { |         test "fromMember populates with specific format" { | ||||||
|             let edit = EditMember.fromMember { Member.empty with Format = Some HtmlFormat } |             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" { |         test "empty is as expected" { | ||||||
|             let edit = EditMember.empty |             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.DaysToKeepNew prefs.DaysToKeepNew "The days to keep new were not filled correctly" | ||||||
|             Expect.equal edit.LongTermUpdateWeeks prefs.LongTermUpdateWeeks |             Expect.equal edit.LongTermUpdateWeeks prefs.LongTermUpdateWeeks | ||||||
|                 "The weeks for update were not filled correctly" |                 "The weeks for update were not filled correctly" | ||||||
|             Expect.equal edit.RequestSort (RequestSort.toCode prefs.RequestSort) |             Expect.equal edit.RequestSort (string prefs.RequestSort) "The request sort was not filled correctly" | ||||||
|                 "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.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.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" |                 "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.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" |             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 |             Expect.equal edit.Visibility GroupVisibility.PrivateList | ||||||
|                 "The list visibility was not derived correctly" |                 "The list visibility was not derived correctly" | ||||||
|             Expect.equal edit.PageSize prefs.PageSize "The page size was not filled correctly" |             Expect.equal edit.PageSize prefs.PageSize "The page size was not filled correctly" | ||||||
|             Expect.equal edit.AsOfDate (AsOfDateDisplay.toCode prefs.AsOfDateDisplay) |             Expect.equal edit.AsOfDate (string prefs.AsOfDateDisplay) "The as-of date display was not filled correctly" | ||||||
|                 "The as-of date display was not filled correctly" |  | ||||||
|         } |         } | ||||||
|         test "fromPreferences succeeds for RGB line color and password-protected list" { |         test "fromPreferences succeeds for RGB line color and password-protected list" { | ||||||
|             let prefs = { ListPreferences.empty with LineColor = "#ff0000"; GroupPassword = "pw" } |             let prefs = { ListPreferences.empty with LineColor = "#ff0000"; GroupPassword = "pw" } | ||||||
| @ -326,13 +321,11 @@ let editRequestTests = | |||||||
|         test "empty is as expected" { |         test "empty is as expected" { | ||||||
|             let mt = EditRequest.empty |             let mt = EditRequest.empty | ||||||
|             Expect.equal mt.RequestId emptyGuid "The request ID should be an empty GUID" |             Expect.equal mt.RequestId emptyGuid "The request ID should be an empty GUID" | ||||||
|             Expect.equal mt.RequestType (PrayerRequestType.toCode CurrentRequest) |             Expect.equal mt.RequestType (string CurrentRequest) "The request type should have been \"Current\"" | ||||||
|                 "The request type should have been \"Current\"" |  | ||||||
|             Expect.isNone mt.EnteredDate "The entered date should have been None" |             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.SkipDateUpdate """The "skip date update" flag should have been None""" | ||||||
|             Expect.isNone mt.Requestor "The requestor should have been None" |             Expect.isNone mt.Requestor "The requestor should have been None" | ||||||
|             Expect.equal mt.Expiration (Expiration.toCode Automatic) |             Expect.equal mt.Expiration (string Automatic) """The expiration should have been "A" (Automatic)""" | ||||||
|                 """The expiration should have been "A" (Automatic)""" |  | ||||||
|             Expect.equal mt.Text "" "The text should have been blank" |             Expect.equal mt.Text "" "The text should have been blank" | ||||||
|         } |         } | ||||||
|         test "fromRequest succeeds" { |         test "fromRequest succeeds" { | ||||||
| @ -346,10 +339,9 @@ let editRequestTests = | |||||||
|                 } |                 } | ||||||
|             let edit = EditRequest.fromRequest req |             let edit = EditRequest.fromRequest req | ||||||
|             Expect.equal edit.RequestId (shortGuid req.Id.Value) "The request ID was not filled correctly" |             Expect.equal edit.RequestId (shortGuid req.Id.Value) "The request ID was not filled correctly" | ||||||
|             Expect.equal edit.RequestType (PrayerRequestType.toCode req.RequestType) |             Expect.equal edit.RequestType (string req.RequestType) "The request type was not filled correctly" | ||||||
|                 "The request type was not filled correctly" |  | ||||||
|             Expect.equal edit.Requestor req.Requestor "The requestor 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" |             Expect.equal edit.Text req.Text "The text was not filled correctly" | ||||||
|         } |         } | ||||||
|         test "isNew works for a new request" { |         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"] ] |                 label [ _for (nameof model.RequestType) ] [ locStr s["Request Type"] ] | ||||||
|                 ReferenceList.requestTypeList s |                 ReferenceList.requestTypeList s | ||||||
|                 |> Seq.ofList |                 |> 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 ] |                 |> selectList (nameof model.RequestType) model.RequestType [ _required; _autofocus ] | ||||||
|             ] |             ] | ||||||
|             div [ _inputField ] [ |             div [ _inputField ] [ | ||||||
|  | |||||||
| @ -54,8 +54,8 @@ let announcement isAdmin ctx viewInfo = | |||||||
|                 label [ _for (nameof model.RequestType) ] [ locStr s["Request Type"] ] |                 label [ _for (nameof model.RequestType) ] [ locStr s["Request Type"] ] | ||||||
|                 reqTypes |                 reqTypes | ||||||
|                 |> Seq.ofList |                 |> 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) (PrayerRequestType.toCode Announcement) [] |                 |> selectList (nameof model.RequestType) (string Announcement) [] | ||||||
|             ] |             ] | ||||||
|         ] |         ] | ||||||
|         div [ _fieldRow ] [ submit [] "send" s["Send 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.Name ] | ||||||
|                         div [ _class "cell" ] [ str mbr.Email ] |                         div [ _class "cell" ] [ str mbr.Email ] | ||||||
|                         div [ _class "cell" ] [ |                         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 |     /// A localized list of the AsOfDateDisplay DU cases | ||||||
|     let asOfDateList (s: IStringLocalizer) = [ |     let asOfDateList (s: IStringLocalizer) = [ | ||||||
|         AsOfDateDisplay.toCode NoDisplay, s["Do not display the “as of” date"] |         string NoDisplay, s["Do not display the “as of” date"] | ||||||
|         AsOfDateDisplay.toCode ShortDate, s["Display a short “as of” date"] |         string ShortDate, s["Display a short “as of” date"] | ||||||
|         AsOfDateDisplay.toCode LongDate,  s["Display a full “as of” date"] |         string LongDate,  s["Display a full “as of” date"] | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
|     /// A list of e-mail type options |     /// 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 |             s[match def with HtmlFormat -> "HTML Format" | PlainTextFormat -> "Plain-Text Format"].Value | ||||||
|         seq { |         seq { | ||||||
|             "", LocalizedString ("", $"""{s["Group Default"].Value} ({defaultType})""") |             "", LocalizedString ("", $"""{s["Group Default"].Value} ({defaultType})""") | ||||||
|             EmailFormat.toCode HtmlFormat,      s["HTML Format"] |             string HtmlFormat,      s["HTML Format"] | ||||||
|             EmailFormat.toCode PlainTextFormat, s["Plain-Text Format"] |             string PlainTextFormat, s["Plain-Text Format"] | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|     /// A list of expiration options |     /// A list of expiration options | ||||||
|     let expirationList (s: IStringLocalizer) includeExpireNow = [ |     let expirationList (s: IStringLocalizer) includeExpireNow = | ||||||
|         Expiration.toCode Automatic, s["Expire Normally"] |         [ string Automatic, s["Expire Normally"] | ||||||
|         Expiration.toCode Manual,    s["Request Never Expires"] |           string Manual,    s["Request Never Expires"] | ||||||
|         if includeExpireNow then Expiration.toCode Forced, s["Expire Immediately"] |           if includeExpireNow then string Forced, s["Expire Immediately"] ] | ||||||
|     ] |  | ||||||
| 
 | 
 | ||||||
|     /// A list of request types |     /// A list of request types | ||||||
|     let requestTypeList (s: IStringLocalizer) = [ |     let requestTypeList (s: IStringLocalizer) = [ | ||||||
| @ -326,7 +325,7 @@ module EditMember = | |||||||
|         {   MemberId = shortGuid mbr.Id.Value |         {   MemberId = shortGuid mbr.Id.Value | ||||||
|             Name     = mbr.Name |             Name     = mbr.Name | ||||||
|             Email    = mbr.Email |             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 |     /// An empty instance | ||||||
| @ -413,10 +412,10 @@ with | |||||||
|             DaysToExpire        = this.ExpireDays |             DaysToExpire        = this.ExpireDays | ||||||
|             DaysToKeepNew       = this.DaysToKeepNew |             DaysToKeepNew       = this.DaysToKeepNew | ||||||
|             LongTermUpdateWeeks = this.LongTermUpdateWeeks |             LongTermUpdateWeeks = this.LongTermUpdateWeeks | ||||||
|             RequestSort         = RequestSort.fromCode this.RequestSort |             RequestSort         = RequestSort.Parse this.RequestSort | ||||||
|             EmailFromName       = this.EmailFromName |             EmailFromName       = this.EmailFromName | ||||||
|             EmailFromAddress    = this.EmailFromAddress |             EmailFromAddress    = this.EmailFromAddress | ||||||
|             DefaultEmailType    = EmailFormat.fromCode this.DefaultEmailType |             DefaultEmailType    = EmailFormat.Parse this.DefaultEmailType | ||||||
|             LineColor           = this.LineColor |             LineColor           = this.LineColor | ||||||
|             HeadingColor        = this.HeadingColor |             HeadingColor        = this.HeadingColor | ||||||
|             Fonts               = if this.IsNative || Option.isNone this.Fonts then "native" else this.Fonts.Value |             Fonts               = if this.IsNative || Option.isNone this.Fonts then "native" else this.Fonts.Value | ||||||
| @ -426,7 +425,7 @@ with | |||||||
|             IsPublic            = isPublic |             IsPublic            = isPublic | ||||||
|             GroupPassword       = grpPw |             GroupPassword       = grpPw | ||||||
|             PageSize            = this.PageSize |             PageSize            = this.PageSize | ||||||
|             AsOfDateDisplay     = AsOfDateDisplay.fromCode this.AsOfDate |             AsOfDateDisplay     = AsOfDateDisplay.Parse this.AsOfDate | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| /// Support for the EditPreferences type | /// Support for the EditPreferences type | ||||||
| @ -437,10 +436,10 @@ module EditPreferences = | |||||||
|         {   ExpireDays          = prefs.DaysToExpire |         {   ExpireDays          = prefs.DaysToExpire | ||||||
|             DaysToKeepNew       = prefs.DaysToKeepNew |             DaysToKeepNew       = prefs.DaysToKeepNew | ||||||
|             LongTermUpdateWeeks = prefs.LongTermUpdateWeeks |             LongTermUpdateWeeks = prefs.LongTermUpdateWeeks | ||||||
|             RequestSort         = RequestSort.toCode prefs.RequestSort |             RequestSort         = string prefs.RequestSort | ||||||
|             EmailFromName       = prefs.EmailFromName |             EmailFromName       = prefs.EmailFromName | ||||||
|             EmailFromAddress    = prefs.EmailFromAddress |             EmailFromAddress    = prefs.EmailFromAddress | ||||||
|             DefaultEmailType    = EmailFormat.toCode prefs.DefaultEmailType |             DefaultEmailType    = string prefs.DefaultEmailType | ||||||
|             LineColorType       = setType prefs.LineColor |             LineColorType       = setType prefs.LineColor | ||||||
|             LineColor           = prefs.LineColor |             LineColor           = prefs.LineColor | ||||||
|             HeadingColorType    = setType prefs.HeadingColor |             HeadingColorType    = setType prefs.HeadingColor | ||||||
| @ -452,7 +451,7 @@ module EditPreferences = | |||||||
|             TimeZone            = TimeZoneId.toString prefs.TimeZoneId |             TimeZone            = TimeZoneId.toString prefs.TimeZoneId | ||||||
|             GroupPassword       = Some prefs.GroupPassword |             GroupPassword       = Some prefs.GroupPassword | ||||||
|             PageSize            = prefs.PageSize |             PageSize            = prefs.PageSize | ||||||
|             AsOfDate            = AsOfDateDisplay.toCode prefs.AsOfDateDisplay |             AsOfDate            = string prefs.AsOfDateDisplay | ||||||
|             Visibility          = |             Visibility          = | ||||||
|                 if   prefs.IsPublic           then GroupVisibility.PublicList |                 if   prefs.IsPublic           then GroupVisibility.PublicList | ||||||
|                 elif prefs.GroupPassword = "" then GroupVisibility.PrivateList |                 elif prefs.GroupPassword = "" then GroupVisibility.PrivateList | ||||||
| @ -495,11 +494,11 @@ module EditRequest = | |||||||
|     /// An empty instance to use for new requests |     /// An empty instance to use for new requests | ||||||
|     let empty = |     let empty = | ||||||
|         {   RequestId      = emptyGuid |         {   RequestId      = emptyGuid | ||||||
|             RequestType    = PrayerRequestType.toCode CurrentRequest |             RequestType    = string CurrentRequest | ||||||
|             EnteredDate    = None |             EnteredDate    = None | ||||||
|             SkipDateUpdate = None |             SkipDateUpdate = None | ||||||
|             Requestor      = None |             Requestor      = None | ||||||
|             Expiration     = Expiration.toCode Automatic |             Expiration     = string Automatic | ||||||
|             Text           = "" |             Text           = "" | ||||||
|         } |         } | ||||||
|      |      | ||||||
| @ -507,9 +506,9 @@ module EditRequest = | |||||||
|     let fromRequest (req: PrayerRequest) = |     let fromRequest (req: PrayerRequest) = | ||||||
|         { empty with |         { empty with | ||||||
|             RequestId   = shortGuid req.Id.Value |             RequestId   = shortGuid req.Id.Value | ||||||
|             RequestType = PrayerRequestType.toCode req.RequestType |             RequestType = string req.RequestType | ||||||
|             Requestor   = req.Requestor |             Requestor   = req.Requestor | ||||||
|             Expiration  = Expiration.toCode req.Expiration |             Expiration  = string req.Expiration | ||||||
|             Text        = req.Text |             Text        = req.Text | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -238,10 +238,10 @@ let save : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun next ct | |||||||
|             let now  = SmallGroup.localDateNow ctx.Clock group |             let now  = SmallGroup.localDateNow ctx.Clock group | ||||||
|             let updated = |             let updated = | ||||||
|                 { pr with |                 { 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 |                     Requestor   = match model.Requestor with Some x when x.Trim() = "" -> None | x -> x | ||||||
|                     Text        = ckEditorToText model.Text |                     Text        = ckEditorToText model.Text | ||||||
|                     Expiration  = Expiration.fromCode model.Expiration |                     Expiration  = Expiration.Parse model.Expiration | ||||||
|                 } |                 } | ||||||
|                 |> function |                 |> function | ||||||
|                 | it when model.IsNew -> |                 | it when model.IsNew -> | ||||||
|  | |||||||
| @ -210,7 +210,7 @@ let saveMember : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun n | |||||||
|                     { mbr with |                     { mbr with | ||||||
|                         Name   = model.Name |                         Name   = model.Name | ||||||
|                         Email  = model.Email |                         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() |             let act = ctx.Strings[if model.IsNew then "Added" else "Updated"].Value.ToLower() | ||||||
|             addInfo ctx ctx.Strings["Successfully {0} group member", act] |             addInfo ctx ctx.Strings["Successfully {0} group member", act] | ||||||
|             return! redirectTo false "/small-group/members" next ctx |             return! redirectTo false "/small-group/members" next ctx | ||||||
| @ -288,7 +288,7 @@ let sendAnnouncement : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> | |||||||
|                         Id           = (Guid.NewGuid >> PrayerRequestId) () |                         Id           = (Guid.NewGuid >> PrayerRequestId) () | ||||||
|                         SmallGroupId = group.Id |                         SmallGroupId = group.Id | ||||||
|                         UserId       = usr.Id |                         UserId       = usr.Id | ||||||
|                         RequestType  = (Option.get >> PrayerRequestType.fromCode) model.RequestType |                         RequestType  = (Option.get >> PrayerRequestType.Parse) model.RequestType | ||||||
|                         Text         = requestText |                         Text         = requestText | ||||||
|                         EnteredDate  = now.Date.AtStartOfDayInZone(zone).ToInstant() |                         EnteredDate  = now.Date.AtStartOfDayInZone(zone).ToInstant() | ||||||
|                         UpdatedDate  = now.InZoneLeniently(zone).ToInstant() } |                         UpdatedDate  = now.InZoneLeniently(zone).ToInstant() } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user