Update to F# 5 (#27)
This commit is contained in:
		
							parent
							
								
									e3583f9152
								
							
						
					
					
						commit
						b0d3bd4e35
					
				| @ -1,9 +1,9 @@ | ||||
| <Project> | ||||
|   <PropertyGroup> | ||||
|     <AssemblyVersion>7.4.2.0</AssemblyVersion> | ||||
|     <FileVersion>7.4.2.0</FileVersion> | ||||
|     <AssemblyVersion>7.5.0.0</AssemblyVersion> | ||||
|     <FileVersion>7.5.0.0</FileVersion> | ||||
|     <Authors>danieljsummers</Authors> | ||||
|     <Company>Bit Badger Solutions</Company> | ||||
|     <Version>7.4.2</Version> | ||||
|     <Version>7.5.0</Version> | ||||
|   </PropertyGroup> | ||||
| </Project> | ||||
|  | ||||
| @ -239,7 +239,7 @@ type AppDbContext with | ||||
|           } | ||||
|       let! grps = q.ToListAsync () | ||||
|       return grps | ||||
|         |> Seq.map (fun grp -> grp.smallGroupId.ToString "N", sprintf "%s | %s" grp.church.name grp.name) | ||||
|         |> Seq.map (fun grp -> grp.smallGroupId.ToString "N", $"{grp.church.name} | {grp.name}") | ||||
|         |> List.ofSeq | ||||
|       } | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>netstandard2.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
| @ -20,8 +20,4 @@ | ||||
|     <PackageReference Include="TaskBuilder.fs" Version="2.1.0" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <PackageReference Update="FSharp.Core" Version="4.7.0" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
| </Project> | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
| @ -26,8 +26,4 @@ | ||||
|     <ProjectReference Include="..\PrayerTracker\PrayerTracker.fsproj" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <PackageReference Update="FSharp.Core" Version="4.7.0" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
| </Project> | ||||
|  | ||||
| @ -74,15 +74,15 @@ let maintain (churches : Church list) (stats : Map<string, ChurchStats>) ctx vi | ||||
|           churches | ||||
|           |> List.map (fun ch -> | ||||
|               let chId      = flatGuid ch.churchId | ||||
|               let delAction = sprintf "/web/church/%s/delete" chId | ||||
|               let delAction = $"/web/church/{chId}/delete" | ||||
|               let delPrompt = s.["Are you sure you want to delete this {0}?  This action cannot be undone.", | ||||
|                                   sprintf "%s (%s)" (s.["Church"].Value.ToLower ()) ch.name] | ||||
|                                   $"""{s.["Church"].Value.ToLower ()} ({ch.name})"""] | ||||
|               tr [] [ | ||||
|                 td [] [ | ||||
|                   a [ _href (sprintf "/web/church/%s/edit" chId); _title s.["Edit This Church"].Value ] [ icon "edit" ] | ||||
|                   a [ _href $"/web/church/{chId}/edit"; _title s.["Edit This Church"].Value ] [ icon "edit" ] | ||||
|                   a [ _href delAction | ||||
|                       _title s.["Delete This Church"].Value | ||||
|                       _onclick (sprintf "return PT.confirmDelete('%s','%A')" delAction delPrompt) ] | ||||
|                       _onclick $"return PT.confirmDelete('{delAction}','{delPrompt}')" ] | ||||
|                     [ icon "delete_forever" ] | ||||
|                   ] | ||||
|                 td [] [ str ch.name ] | ||||
| @ -96,7 +96,7 @@ let maintain (churches : Church list) (stats : Map<string, ChurchStats>) ctx vi | ||||
|           ] | ||||
|   [ div [ _class "pt-center-text" ] [ | ||||
|       br [] | ||||
|       a [ _href (sprintf "/web/church/%s/edit" emptyGuid); _title s.["Add a New Church"].Value ] | ||||
|       a [ _href $"/web/church/{emptyGuid}/edit"; _title s.["Add a New Church"].Value ] | ||||
|         [ icon "add_circle"; rawText "  "; locStr s.["Add a New Church"] ] | ||||
|       br [] | ||||
|       br [] | ||||
|  | ||||
| @ -28,7 +28,7 @@ let space = rawText " " | ||||
| let icon name = i [ _class "material-icons" ] [ rawText name ] | ||||
| 
 | ||||
| /// Generate a Material Design icon, specifying the point size (must be defined in CSS) | ||||
| let iconSized size name = i [ _class (sprintf "material-icons md-%i" size) ] [ rawText name ] | ||||
| let iconSized size name = i [ _class $"material-icons md-{size}" ] [ rawText name ] | ||||
| 
 | ||||
| /// Generate a CSRF prevention token | ||||
| let csrfToken (ctx : HttpContext) = | ||||
| @ -72,7 +72,7 @@ let namedColorList name selected attrs (s : IStringLocalizer) = | ||||
|   |> Seq.map (fun color -> | ||||
|       let (colorName, dispText, txtColor) = color | ||||
|       option [ yield _value colorName | ||||
|                yield _style (sprintf "background-color:%s;color:%s;" colorName txtColor) | ||||
|                yield _style $"background-color:{colorName};color:{txtColor};" | ||||
|                match colorName = selected with true -> yield _selected | false -> () ] [ | ||||
|         encodedText (dispText.Value.ToLower ()) | ||||
|         ]) | ||||
| @ -97,7 +97,7 @@ let selectList name selected attrs items = | ||||
|   |> select (List.concat [ [ _name name; _id name ]; attrs ]) | ||||
| 
 | ||||
| /// Generate the text for a default entry at the top of a select list | ||||
| let selectDefault text = sprintf "— %s —" text | ||||
| let selectDefault text = $"— {text} —" | ||||
| 
 | ||||
| /// Generate a standard submit button with icon and text | ||||
| let submit attrs ico text = button (_type "submit" :: attrs) [ icon ico; rawText "  "; locStr text ] | ||||
| @ -115,7 +115,7 @@ let blockquote = tag "blockquote" | ||||
| /// role attribute | ||||
| let _role = attr "role" | ||||
| /// aria-* attribute | ||||
| let _aria typ = attr (sprintf "aria-%s" typ) | ||||
| let _aria typ = attr $"aria-{typ}" | ||||
| /// onclick attribute | ||||
| let _onclick = attr "onclick" | ||||
| /// onsubmit attribute | ||||
|  | ||||
| @ -35,9 +35,9 @@ let error code vi = | ||||
|     br [] | ||||
|     hr [] | ||||
|     div [ _style "font-size:70%;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',sans-serif" ] [ | ||||
|       img [ _src (sprintf "/img/%A.png" s.["footer_en"]) | ||||
|             _alt (sprintf "%A %A" s.["PrayerTracker"] s.["from Bit Badger Solutions"]) | ||||
|             _title (sprintf "%A %A" s.["PrayerTracker"] s.["from Bit Badger Solutions"]) | ||||
|       img [ _src $"""/img/%A{s.["footer_en"]}.png""" | ||||
|             _alt $"""%A{s.["PrayerTracker"]} %A{s.["from Bit Badger Solutions"]}""" | ||||
|             _title $"""%A{s.["PrayerTracker"]} %A{s.["from Bit Badger Solutions"]}""" | ||||
|             _style "vertical-align:text-bottom;" ] | ||||
|       str vi.version | ||||
|       ] | ||||
|  | ||||
| @ -19,4 +19,4 @@ let localizer = lazy (stringLocFactory.Create ("Common", resAsmName)) | ||||
|    | ||||
| /// Get a view localizer | ||||
| let forView (view : string) = | ||||
|   htmlLocFactory.Create (sprintf "Views.%s" (view.Replace ('/', '.')), resAsmName) | ||||
|   htmlLocFactory.Create ($"""Views.{view.Replace ('/', '.')}""", resAsmName) | ||||
|  | ||||
| @ -76,7 +76,7 @@ module Navigation = | ||||
|                   [ icon "list"; space; locStr s.["View Request List"] ] | ||||
|                 ] | ||||
|       li [] [ | ||||
|         a [ _href   (sprintf "https://docs.prayer.bitbadger.solutions/%s" <| langCode ()) | ||||
|         a [ _href   $"https://docs.prayer.bitbadger.solutions/{langCode ()}" | ||||
|             _aria   "label" s.["Help"].Value; | ||||
|             _title  s.["View Help"].Value | ||||
|             _target "_blank" | ||||
| @ -183,9 +183,9 @@ let private htmlHead m pageTitle = | ||||
|     title [] [ locStr pageTitle; titleSep; locStr s.["PrayerTracker"] ] | ||||
|     yield! commonHead | ||||
|     for cssFile in m.style do | ||||
|       link [ _rel "stylesheet"; _href (sprintf "/css/%s.css" cssFile); _type "text/css" ] | ||||
|       link [ _rel "stylesheet"; _href $"/css/{cssFile}.css"; _type "text/css" ] | ||||
|     for jsFile in m.script do | ||||
|       script [ _src (sprintf "/js/%s.js" jsFile) ] [] | ||||
|       script [ _src $"/js/{jsFile}.js" ] [] | ||||
|     ] | ||||
|    | ||||
| /// Render a link to the help page for the current page | ||||
| @ -194,7 +194,7 @@ let private helpLink link = | ||||
|   sup [] [ | ||||
|     a [ _href link | ||||
|         _title s.["Click for Help on This Page"].Value | ||||
|         _onclick (sprintf "return PT.showHelp('%s')" link) ] [ | ||||
|         _onclick $"return PT.showHelp('{link}')" ] [ | ||||
|       icon "help_outline" | ||||
|       ] | ||||
|     ] | ||||
| @ -211,7 +211,7 @@ let private messages m = | ||||
|   let s = I18N.localizer.Force () | ||||
|   m.messages | ||||
|   |> List.map (fun msg -> | ||||
|       table [ _class (sprintf "pt-msg %s" (msg.level.ToLower ())) ] [ | ||||
|       table [ _class $"pt-msg {msg.level.ToLower ()}" ] [ | ||||
|         tr [] [ | ||||
|           td [] [ | ||||
|             match msg.level with | ||||
| @ -249,7 +249,7 @@ let private htmlFooter m = | ||||
|       ] | ||||
|     div [ _id "pt-footer" ] [ | ||||
|       a [ _href "/web/"; _style "line-height:28px;" ] [ | ||||
|         img [ _src (sprintf "/img/%O.png" s.["footer_en"]); _alt imgText; _title imgText ] | ||||
|         img [ _src $"""/img/%O{s.["footer_en"]}.png"""; _alt imgText; _title imgText ] | ||||
|         ] | ||||
|       str m.version | ||||
|       space | ||||
|  | ||||
| @ -55,7 +55,7 @@ let edit (m : EditRequest) today ctx vi = | ||||
|           label [] [ locStr s.["Expiration"] ] | ||||
|           ReferenceList.expirationList s ((m.isNew >> not) ()) | ||||
|           |> List.map (fun exp -> | ||||
|               let radioId = sprintf "expiration_%s" (fst exp) | ||||
|               let radioId = $"expiration_{fst exp}" | ||||
|               span [ _class "text-nowrap" ] [ | ||||
|                 radio "expiration" radioId (fst exp) m.expiration | ||||
|                 label [ _for radioId ] [ locStr (snd exp) ] | ||||
| @ -80,13 +80,13 @@ let edit (m : EditRequest) today ctx vi = | ||||
| /// View for the request e-mail results page | ||||
| let email m vi = | ||||
|   let s         = I18N.localizer.Force () | ||||
|   let pageTitle = sprintf "%s • %s" s.["Prayer Requests"].Value m.listGroup.name | ||||
|   let pageTitle = $"""{s.["Prayer Requests"].Value} • {m.listGroup.name}""" | ||||
|   let prefs     = m.listGroup.preferences | ||||
|   let addresses = | ||||
|     m.recipients | ||||
|     |> List.fold (fun (acc : StringBuilder) mbr -> acc.AppendFormat(", {0} <{1}>", mbr.memberName, mbr.email)) | ||||
|                  (StringBuilder ()) | ||||
|   [ p [ _style (sprintf "font-family:%s;font-size:%ipt;" prefs.listFonts prefs.textFontSize) ] [ | ||||
|   [ p [ _style $"font-family:{prefs.listFonts};font-size:%i{prefs.textFontSize}pt;" ] [ | ||||
|       locStr s.["The request list was sent to the following people, via individual e-mails"] | ||||
|       rawText ":" | ||||
|       br [] | ||||
| @ -143,9 +143,9 @@ let lists (grps : SmallGroup list) vi = | ||||
|               tr [] [ | ||||
|                 match grp.preferences.isPublic with | ||||
|                 | true -> | ||||
|                     a [ _href (sprintf "/web/prayer-requests/%s/list" grpId); _title s.["View"].Value ] [ icon "list" ] | ||||
|                     a [ _href $"/web/prayer-requests/{grpId}/list"; _title s.["View"].Value ] [ icon "list" ] | ||||
|                 | false -> | ||||
|                     a [ _href (sprintf "/web/small-group/log-on/%s" grpId); _title s.["Log On"].Value ] | ||||
|                     a [ _href $"/web/small-group/log-on/{grpId}"; _title s.["Log On"].Value ] | ||||
|                       [ icon "verified_user" ] | ||||
|                 |> List.singleton | ||||
|                 |> td [] | ||||
| @ -179,8 +179,8 @@ let maintain m (ctx : HttpContext) vi = | ||||
|     m.requests | ||||
|     |> Seq.map (fun req -> | ||||
|         let reqId     = flatGuid req.prayerRequestId | ||||
|         let reqText   = Utils.htmlToPlainText req.text | ||||
|         let delAction = sprintf "/web/prayer-request/%s/delete" reqId | ||||
|         let reqText   = htmlToPlainText req.text | ||||
|         let delAction = $"/web/prayer-request/{reqId}/delete" | ||||
|         let delPrompt = | ||||
|           [ s.["Are you sure you want to delete this {0}?  This action cannot be undone.", | ||||
|                 s.["Prayer Request"].Value.ToLower() ] | ||||
| @ -192,36 +192,36 @@ let maintain m (ctx : HttpContext) vi = | ||||
|           |> String.concat "" | ||||
|         tr [] [ | ||||
|           td [] [ | ||||
|             a [ _href (sprintf "/web/prayer-request/%s/edit" reqId); _title l.["Edit This Prayer Request"].Value ] | ||||
|             a [ _href $"/web/prayer-request/{reqId}/edit"; _title l.["Edit This Prayer Request"].Value ] | ||||
|               [ icon "edit" ] | ||||
|             match req.isExpired now m.smallGroup.preferences.daysToExpire with | ||||
|             | true -> | ||||
|                 a [ _href (sprintf "/web/prayer-request/%s/restore" reqId) | ||||
|                 a [ _href $"/web/prayer-request/{reqId}/restore" | ||||
|                     _title l.["Restore This Inactive Request"].Value ] | ||||
|                   [ icon "visibility" ] | ||||
|             | false -> | ||||
|                 a [ _href (sprintf "/web/prayer-request/%s/expire" reqId) | ||||
|                 a [ _href $"/web/prayer-request/{reqId}/expire" | ||||
|                     _title l.["Expire This Request Immediately"].Value ] | ||||
|                   [ icon "visibility_off" ] | ||||
|             a [ _href delAction; _title l.["Delete This Request"].Value; | ||||
|                 _onclick (sprintf "return PT.confirmDelete('%s','%s')" delAction delPrompt) ] | ||||
|                 _onclick $"return PT.confirmDelete('{delAction}','{delPrompt}')" ] | ||||
|               [ icon "delete_forever" ] | ||||
|             ] | ||||
|           td [ updReq req ] [ | ||||
|             str (req.updatedDate.ToString(s.["MMMM d, yyyy"].Value, System.Globalization.CultureInfo.CurrentUICulture)) | ||||
|             str (req.updatedDate.ToString(s.["MMMM d, yyyy"].Value, Globalization.CultureInfo.CurrentUICulture)) | ||||
|             ] | ||||
|           td [] [ locStr typs.[req.requestType] ] | ||||
|           td [ reqExp req ] [ str (match req.requestor with Some r -> r | None -> " ") ] | ||||
|           td [] [ | ||||
|             match reqText.Length with | ||||
|             | len when len < 60 -> rawText reqText | ||||
|             | _ -> rawText (sprintf "%s…" reqText.[0..59]) | ||||
|             | _ -> rawText $"{reqText.[0..59]}…" | ||||
|             ] | ||||
|           ]) | ||||
|     |> List.ofSeq | ||||
|   [ div [ _class "pt-center-text" ] [ | ||||
|       br [] | ||||
|       a [ _href (sprintf "/web/prayer-request/%s/edit" emptyGuid); _title s.["Add a New Request"].Value ] | ||||
|       a [ _href $"/web/prayer-request/{emptyGuid}/edit"; _title s.["Add a New Request"].Value ] | ||||
|         [ icon "add_circle"; rawText "  "; locStr s.["Add a New Request"] ] | ||||
|       rawText "       " | ||||
|       a [ _href "/web/prayer-requests/view"; _title s.["View Prayer Request List"].Value ] | ||||
| @ -302,14 +302,14 @@ let maintain m (ctx : HttpContext) vi = | ||||
| /// View for the printable prayer request list | ||||
| let print m version = | ||||
|   let s         = I18N.localizer.Force () | ||||
|   let pageTitle = sprintf "%s • %s" s.["Prayer Requests"].Value m.listGroup.name | ||||
|   let imgAlt    = sprintf "%s %s" s.["PrayerTracker"].Value s.["from Bit Badger Solutions"].Value | ||||
|   let pageTitle = $"""{s.["Prayer Requests"].Value} • {m.listGroup.name}""" | ||||
|   let imgAlt    = $"""{s.["PrayerTracker"].Value} {s.["from Bit Badger Solutions"].Value}""" | ||||
|   article [] [ | ||||
|     rawText (m.asHtml s) | ||||
|     br [] | ||||
|     hr [] | ||||
|     div [ _style "font-size:70%;font-family:@Model.ListGroup.preferences.listFonts;" ] [ | ||||
|       img [ _src (sprintf "/img/%s.png" s.["footer_en"].Value) | ||||
|     div [ _style $"font-size:70%%;font-family:{m.listGroup.preferences.listFonts};" ] [ | ||||
|       img [ _src $"""/img/{s.["footer_en"].Value}.png""" | ||||
|             _style "vertical-align:text-bottom;" | ||||
|             _alt imgAlt | ||||
|             _title imgAlt ] | ||||
| @ -323,13 +323,13 @@ let print m version = | ||||
| /// View for the prayer request list | ||||
| let view m vi = | ||||
|   let s         = I18N.localizer.Force () | ||||
|   let pageTitle = sprintf "%s • %s" s.["Prayer Requests"].Value m.listGroup.name | ||||
|   let pageTitle = $"""{s.["Prayer Requests"].Value} • {m.listGroup.name}""" | ||||
|   let spacer    = rawText "       " | ||||
|   let dtString  = m.date.ToString "yyyy-MM-dd" | ||||
|   [ div [ _class "pt-center-text" ] [ | ||||
|       br [] | ||||
|       a [ _class "pt-icon-link" | ||||
|           _href (sprintf "/web/prayer-requests/print/%s" dtString) | ||||
|           _href $"/web/prayer-requests/print/{dtString}" | ||||
|           _title s.["View Printable"].Value ] [ | ||||
|         icon "print"; rawText "  "; locStr s.["View Printable"] | ||||
|         ] | ||||
| @ -345,16 +345,16 @@ let view m vi = | ||||
|                 | false -> findSunday (date.AddDays 1.) | ||||
|               let sunday = findSunday m.date | ||||
|               a [ _class "pt-icon-link" | ||||
|                   _href (sprintf "/web/prayer-requests/view/%s" (sunday.ToString "yyyy-MM-dd")) | ||||
|                   _href $"""/web/prayer-requests/view/{sunday.ToString "yyyy-MM-dd"}""" | ||||
|                   _title s.["List for Next Sunday"].Value ] [ | ||||
|                 icon "update"; rawText "  "; locStr s.["List for Next Sunday"] | ||||
|                 ] | ||||
|               spacer | ||||
|           let emailPrompt = s.["This will e-mail the current list to every member of your group, without further prompting.  Are you sure this is what you are ready to do?"].Value | ||||
|           a [ _class "pt-icon-link" | ||||
|               _href (sprintf "/web/prayer-requests/email/%s" dtString) | ||||
|               _href $"/web/prayer-requests/email/{dtString}" | ||||
|               _title s.["Send via E-mail"].Value | ||||
|               _onclick (sprintf "return PT.requests.view.promptBeforeEmail('%s')" emailPrompt) ] [ | ||||
|               _onclick $"return PT.requests.view.promptBeforeEmail('{emailPrompt}')" ] [ | ||||
|             icon "mail_outline"; rawText "  "; locStr s.["Send via E-mail"] | ||||
|             ] | ||||
|           spacer | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>netstandard2.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
| @ -61,8 +61,4 @@ | ||||
|     </EmbeddedResource> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <PackageReference Update="FSharp.Core" Version="4.7.0" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
| </Project> | ||||
|  | ||||
| @ -147,7 +147,7 @@ let logOn (grps : SmallGroup list) grpId ctx vi = | ||||
|             | _ -> | ||||
|                 "", selectDefault s.["Select Group"].Value | ||||
|                 yield! grps | ||||
|                   |> List.map (fun grp -> flatGuid grp.smallGroupId, sprintf "%s | %s" grp.church.name grp.name) | ||||
|                   |> List.map (fun grp -> flatGuid grp.smallGroupId, $"{grp.church.name} | {grp.name}") | ||||
|             } | ||||
|           |> selectList "smallGroupId" grpId [ _required ] | ||||
|           ] | ||||
| @ -190,15 +190,15 @@ let maintain (grps : SmallGroup list) ctx vi = | ||||
|           grps | ||||
|           |> List.map (fun g -> | ||||
|               let grpId     = flatGuid g.smallGroupId | ||||
|               let delAction = sprintf "/web/small-group/%s/delete" grpId | ||||
|               let delAction = $"/web/small-group/{grpId}/delete" | ||||
|               let delPrompt = s.["Are you sure you want to delete this {0}?  This action cannot be undone.", | ||||
|                                    sprintf "%s (%s)" (s.["Small Group"].Value.ToLower ()) g.name].Value | ||||
|                                    $"""{s.["Small Group"].Value.ToLower ()} ({g.name})""" ].Value | ||||
|               tr [] [ | ||||
|                 td [] [ | ||||
|                   a [ _href (sprintf "/web/small-group/%s/edit" grpId); _title s.["Edit This Group"].Value ] [ icon "edit" ] | ||||
|                   a [ _href $"/web/small-group/{grpId}/edit"; _title s.["Edit This Group"].Value ] [ icon "edit" ] | ||||
|                   a [ _href delAction | ||||
|                       _title s.["Delete This Group"].Value | ||||
|                       _onclick (sprintf "return PT.confirmDelete('%s','%s')" delAction delPrompt) ] | ||||
|                       _onclick $"return PT.confirmDelete('{delAction}','{delPrompt}')" ] | ||||
|                     [ icon "delete_forever" ] | ||||
|                   ] | ||||
|                 td [] [ str g.name ] | ||||
| @ -209,7 +209,7 @@ let maintain (grps : SmallGroup list) ctx vi = | ||||
|           ] | ||||
|   [ div [ _class "pt-center-text" ] [ | ||||
|       br [] | ||||
|       a [ _href (sprintf "/web/small-group/%s/edit" emptyGuid); _title s.["Add a New Group"].Value ] [ | ||||
|       a [ _href $"/web/small-group/{emptyGuid}/edit"; _title s.["Add a New Group"].Value ] [ | ||||
|         icon "add_circle" | ||||
|         rawText "  " | ||||
|         locStr s.["Add a New Group"] | ||||
| @ -244,18 +244,18 @@ let members (mbrs : Member list) (emailTyps : Map<string, LocalizedString>) ctx | ||||
|           mbrs | ||||
|           |> List.map (fun mbr -> | ||||
|               let mbrId     = flatGuid mbr.memberId | ||||
|               let delAction = sprintf "/web/small-group/member/%s/delete" mbrId | ||||
|               let delAction = $"/web/small-group/member/{mbrId}/delete" | ||||
|               let delPrompt = | ||||
|                 s.["Are you sure you want to delete this {0}?  This action cannot be undone.", s.["group member"]] | ||||
|                   .Value | ||||
|                   .Replace("?", sprintf " (%s)?" mbr.memberName) | ||||
|                   .Replace("?", $" ({mbr.memberName})?") | ||||
|               tr [] [ | ||||
|                 td [] [ | ||||
|                   a [ _href (sprintf "/web/small-group/member/%s/edit" mbrId); _title s.["Edit This Group Member"].Value ] | ||||
|                   a [ _href $"/web/small-group/member/{mbrId}/edit"; _title s.["Edit This Group Member"].Value ] | ||||
|                     [ icon "edit" ] | ||||
|                   a [ _href delAction | ||||
|                       _title s.["Delete This Group Member"].Value | ||||
|                       _onclick (sprintf "return PT.confirmDelete('%s','%s')" delAction delPrompt) ] | ||||
|                       _onclick $"return PT.confirmDelete('{delAction}','{delPrompt}')" ] | ||||
|                     [ icon "delete_forever" ] | ||||
|                   ] | ||||
|                 td [] [ str mbr.memberName ] | ||||
| @ -266,7 +266,7 @@ let members (mbrs : Member list) (emailTyps : Map<string, LocalizedString>) ctx | ||||
|           ] | ||||
|   [ div [ _class"pt-center-text" ] [ | ||||
|       br [] | ||||
|       a [ _href (sprintf "/web/small-group/member/%s/edit" emptyGuid); _title s.["Add a New Group Member"].Value ] | ||||
|       a [ _href $"/web/small-group/member/{emptyGuid}/edit"; _title s.["Add a New Group Member"].Value ] | ||||
|         [ icon "add_circle"; rawText "  "; locStr s.["Add a New Group Member"] ] | ||||
|       br [] | ||||
|       br [] | ||||
|  | ||||
| @ -21,7 +21,7 @@ let assignGroups m groups curGroups ctx vi = | ||||
|         ] | ||||
|       groups | ||||
|       |> List.map (fun (grpId, grpName) -> | ||||
|           let inputId = sprintf "id-%s" grpId | ||||
|           let inputId = $"id-{grpId}" | ||||
|           tr [] [ | ||||
|             td [] [ | ||||
|               input [ _type "checkbox" | ||||
| @ -49,7 +49,7 @@ let changePassword ctx vi = | ||||
|       ] | ||||
|     form [ _action "/web/user/password/change" | ||||
|            _method "post" | ||||
|            _onsubmit (sprintf "return PT.compareValidation('newPassword','newPasswordConfirm','%A')" s.["The passwords do not match"]) ] [ | ||||
|            _onsubmit $"""return PT.compareValidation('newPassword','newPasswordConfirm','%A{s.["The passwords do not match"]}')""" ] [ | ||||
|       style [ _scoped ] [ rawText "#oldPassword, #newPassword, #newPasswordConfirm { width: 10rem; } "] | ||||
|       csrfToken ctx | ||||
|       div [ _class "pt-field-row" ] [ | ||||
| @ -84,7 +84,7 @@ let edit (m : EditUser) ctx vi = | ||||
|   let pageTitle     = match m.isNew () with true -> "Add a New User" | false -> "Edit User" | ||||
|   let pwPlaceholder = s.[match m.isNew () with true -> "" | false -> "No change"].Value | ||||
|   [ form [ _action "/web/user/edit/save"; _method "post"; _class "pt-center-columns" | ||||
|            _onsubmit (sprintf "return PT.compareValidation('password','passwordConfirm','%A')" s.["The passwords do not match"]) ] [ | ||||
|            _onsubmit $"""return PT.compareValidation('password','passwordConfirm','%A{s.["The passwords do not match"]}')""" ] [ | ||||
|       style [ _scoped ] | ||||
|         [ rawText "#firstName, #lastName, #password, #passwordConfirm { width: 10rem; } #emailAddress { width: 20rem; } " ] | ||||
|       csrfToken ctx | ||||
| @ -123,7 +123,7 @@ let edit (m : EditUser) ctx vi = | ||||
|         ] | ||||
|       div [ _class "pt-field-row" ] [ submit [] "save" s.["Save User"] ] | ||||
|       ] | ||||
|     script [] [ rawText (sprintf "PT.onLoad(PT.user.edit.onPageLoad(%s))" ((string (m.isNew ())).ToLower ())) ] | ||||
|     script [] [ rawText $"PT.onLoad(PT.user.edit.onPageLoad({(string (m.isNew ())).ToLower ()}))" ] | ||||
|     ] | ||||
|   |> Layout.Content.standard | ||||
|   |> Layout.standard vi pageTitle | ||||
| @ -189,17 +189,17 @@ let maintain (users : User list) ctx vi = | ||||
|           users | ||||
|           |> List.map (fun user -> | ||||
|               let userId    = flatGuid user.userId | ||||
|               let delAction = sprintf "/web/user/%s/delete" userId | ||||
|               let delAction = $"/web/user/{userId}/delete" | ||||
|               let delPrompt = s.["Are you sure you want to delete this {0}?  This action cannot be undone.", | ||||
|                                   (sprintf "%s (%s)" (s.["User"].Value.ToLower()) user.fullName)].Value | ||||
|                                   $"""{s.["User"].Value.ToLower ()} ({user.fullName})"""].Value | ||||
|               tr [] [ | ||||
|                 td [] [ | ||||
|                   a [ _href (sprintf "/web/user/%s/edit" userId); _title s.["Edit This User"].Value ] [ icon "edit" ] | ||||
|                   a [ _href (sprintf "/web/user/%s/small-groups" userId); _title s.["Assign Groups to This User"].Value ] | ||||
|                   a [ _href $"/web/user/{userId}/edit"; _title s.["Edit This User"].Value ] [ icon "edit" ] | ||||
|                   a [ _href $"/web/user/{userId}/small-groups"; _title s.["Assign Groups to This User"].Value ] | ||||
|                     [ icon "group" ] | ||||
|                   a [ _href delAction | ||||
|                       _title s.["Delete This User"].Value | ||||
|                       _onclick (sprintf "return PT.confirmDelete('%s','%s')" delAction delPrompt) ] | ||||
|                       _onclick $"return PT.confirmDelete('{delAction}','{delPrompt}')" ] | ||||
|                     [ icon "delete_forever" ] | ||||
|                   ] | ||||
|                 td [] [ str user.fullName ] | ||||
| @ -213,7 +213,7 @@ let maintain (users : User list) ctx vi = | ||||
|           ] | ||||
|   [ div [ _class "pt-center-text" ] [ | ||||
|       br [] | ||||
|       a [ _href (sprintf "/web/user/%s/edit" emptyGuid); _title s.["Add a New User"].Value ] | ||||
|       a [ _href $"/web/user/{emptyGuid}/edit"; _title s.["Add a New User"].Value ] | ||||
|         [ icon "add_circle"; rawText "  "; locStr s.["Add a New User"] ] | ||||
|       br [] | ||||
|       br [] | ||||
|  | ||||
| @ -54,9 +54,9 @@ let stripTags allowedTags input = | ||||
|       |> List.fold | ||||
|           (fun acc t -> | ||||
|               acc | ||||
|                 || htmlTag.IndexOf (sprintf "<%s>" t) = 0 | ||||
|                 || htmlTag.IndexOf (sprintf "<%s " t) = 0 | ||||
|                 || htmlTag.IndexOf (sprintf "</%s" t) = 0) false | ||||
|                 || htmlTag.IndexOf $"<{t}>" = 0 | ||||
|                 || htmlTag.IndexOf $"<{t} " = 0 | ||||
|                 || htmlTag.IndexOf $"</{t}" = 0) false | ||||
|     match isAllowed with | ||||
|     | true -> () | ||||
|     | false -> output <- String.replaceFirst tag.Value "" output | ||||
| @ -200,7 +200,7 @@ module Help = | ||||
|   /// Help link for user password change page | ||||
|   let changePassword = "user/password" | ||||
|   /// Create a full link for a help page | ||||
|   let fullLink lang url = sprintf "https://docs.prayer.bitbadger.solutions/%s/%s.html" lang url | ||||
|   let fullLink lang url = $"https://docs.prayer.bitbadger.solutions/%s{lang}/%s{url}.html" | ||||
| 
 | ||||
| /// This class serves as a common anchor for resources | ||||
| type Common () = | ||||
|  | ||||
| @ -25,7 +25,7 @@ module ReferenceList = | ||||
|       | HtmlFormat -> s.["HTML Format"].Value | ||||
|       | PlainTextFormat -> s.["Plain-Text Format"].Value | ||||
|     seq { | ||||
|       "", LocalizedString ("", sprintf "%s (%s)" s.["Group Default"].Value defaultType) | ||||
|       "", LocalizedString ("", $"""{s.["Group Default"].Value} ({defaultType})""") | ||||
|       HtmlFormat.code, s.["HTML Format"] | ||||
|       PlainTextFormat.code, s.["Plain-Text Format"] | ||||
|       } | ||||
| @ -594,12 +594,12 @@ with | ||||
|     let asOfSize = Math.Round (float prefs.textFontSize * 0.8, 2) | ||||
|     [ match this.showHeader with | ||||
|       | true -> | ||||
|           div [ _style (sprintf "text-align:center;font-family:%s" prefs.listFonts) ] [ | ||||
|             span [ _style (sprintf "font-size:%ipt;" prefs.headingFontSize) ] [ | ||||
|           div [ _style $"text-align:center;font-family:{prefs.listFonts}" ] [ | ||||
|             span [ _style $"font-size:%i{prefs.headingFontSize}pt;" ] [ | ||||
|               strong [] [ str s.["Prayer Requests"].Value ] | ||||
|               ] | ||||
|             br [] | ||||
|             span [ _style (sprintf "font-size:%ipt;" prefs.textFontSize) ] [ | ||||
|             span [ _style $"font-size:%i{prefs.textFontSize}pt;" ] [ | ||||
|               strong [] [ str this.listGroup.name ] | ||||
|               br [] | ||||
|               str (this.date.ToString s.["MMMM d, yyyy"].Value) | ||||
| @ -616,10 +616,9 @@ with | ||||
|         let reqs    = this.requestsInCategory cat | ||||
|         let catName = typs |> List.filter (fun t -> fst t = cat) |> List.head |> snd | ||||
|         div [ _style "padding-left:10px;padding-bottom:.5em;" ] [ | ||||
|           table [ _style (sprintf "font-family:%s;page-break-inside:avoid;" prefs.listFonts) ] [ | ||||
|           table [ _style $"font-family:{prefs.listFonts};page-break-inside:avoid;" ] [ | ||||
|             tr [] [ | ||||
|               td [ _style (sprintf "font-size:%ipt;color:%s;padding:3px 0;border-top:solid 3px %s;border-bottom:solid 3px %s;font-weight:bold;" | ||||
|                                       prefs.headingFontSize prefs.headingColor prefs.lineColor prefs.lineColor) ] [ | ||||
|               td [ _style $"font-size:%i{prefs.headingFontSize}pt;color:{prefs.headingColor};padding:3px 0;border-top:solid 3px {prefs.lineColor};border-bottom:solid 3px {prefs.lineColor};font-weight:bold;" ] [ | ||||
|                 rawText "    "; str catName.Value; rawText "    " | ||||
|                 ] | ||||
|               ] | ||||
| @ -628,8 +627,7 @@ with | ||||
|         reqs | ||||
|         |> List.map (fun req -> | ||||
|             let bullet = match this.isNew req with true -> "circle" | false -> "disc" | ||||
|             li [ _style (sprintf "list-style-type:%s;font-family:%s;font-size:%ipt;padding-bottom:.25em;" | ||||
|                                     bullet prefs.listFonts prefs.textFontSize) ] [ | ||||
|             li [ _style $"list-style-type:{bullet};font-family:{prefs.listFonts};font-size:%i{prefs.textFontSize}pt;padding-bottom:.25em;" ] [ | ||||
|               match req.requestor with | ||||
|               | Some rqstr when rqstr <> "" -> | ||||
|                   strong [] [ str rqstr ] | ||||
| @ -646,7 +644,7 @@ with | ||||
|                     | ShortDate -> req.updatedDate.ToShortDateString () | ||||
|                     | LongDate -> req.updatedDate.ToLongDateString () | ||||
|                     | _ -> "" | ||||
|                   i [ _style (sprintf "font-size:%.2fpt" asOfSize) ] [ | ||||
|                   i [ _style $"font-size:%.2f{asOfSize}pt" ] [ | ||||
|                     rawText "  ("; str s.["as of"].Value; str " "; str dt; rawText ")" | ||||
|                     ] | ||||
|               ]) | ||||
| @ -672,7 +670,7 @@ with | ||||
|         let typ    = (typs |> List.filter (fun t -> fst t = cat) |> List.head |> snd).Value | ||||
|         let dashes = String.replicate (typ.Length + 4) "-" | ||||
|         dashes | ||||
|         sprintf @"  %s" (typ.ToUpper ()) | ||||
|         $"  {typ.ToUpper ()}" | ||||
|         dashes | ||||
|         for req in reqs do | ||||
|           let bullet = match this.isNew req with true -> "+" | false -> "-" | ||||
| @ -685,7 +683,7 @@ with | ||||
|                 | ShortDate -> req.updatedDate.ToShortDateString () | ||||
|                 | LongDate -> req.updatedDate.ToLongDateString () | ||||
|                 | _ -> "" | ||||
|               sprintf "  (%s %s)" s.["as of"].Value dt | ||||
|               $"""  ({s.["as of"].Value} {dt})""" | ||||
|           |> sprintf "  %s %s%s%s" bullet requestor (htmlToPlainText req.text) | ||||
|         " " | ||||
|       } | ||||
|  | ||||
| @ -26,7 +26,7 @@ module Configure = | ||||
|   let configuration (ctx : WebHostBuilderContext) (cfg : IConfigurationBuilder) = | ||||
|     cfg.SetBasePath(ctx.HostingEnvironment.ContentRootPath) | ||||
|       .AddJsonFile("appsettings.json", optional = true, reloadOnChange = true) | ||||
|       .AddJsonFile(sprintf "appsettings.%s.json" ctx.HostingEnvironment.EnvironmentName, optional = true) | ||||
|       .AddJsonFile($"appsettings.{ctx.HostingEnvironment.EnvironmentName}.json", optional = true) | ||||
|       .AddEnvironmentVariables() | ||||
|     |> ignore | ||||
| 
 | ||||
|  | ||||
| @ -24,7 +24,7 @@ let toSelectList<'T> valFunc textFunc withDefault emptyText (items : 'T seq) = | ||||
|   [ match withDefault with | ||||
|     | true -> | ||||
|         let s = PrayerTracker.Views.I18N.localizer.Force () | ||||
|         yield SelectListItem (sprintf "— %A —" s.[emptyText], "") | ||||
|         yield SelectListItem ($"""— %A{s.[emptyText]} —""", "") | ||||
|     | _ -> () | ||||
|     yield! items |> Seq.map (fun x -> SelectListItem (textFunc x, valFunc x)) | ||||
|     ] | ||||
| @ -41,15 +41,15 @@ let toSelectListWithDefault<'T> valFunc textFunc (items : 'T seq) = | ||||
| let appVersion = | ||||
|   let v = Assembly.GetExecutingAssembly().GetName().Version | ||||
| #if (DEBUG) | ||||
|   sprintf "v%A" v | ||||
|   $"v{v}" | ||||
| #else | ||||
|   seq { | ||||
|     sprintf "v%d" v.Major | ||||
|     $"v%d{v.Major}" | ||||
|     match v.Minor with | ||||
|     | 0 -> match v.Build with 0 -> () | _ -> sprintf ".0.%d" v.Build | ||||
|     | 0 -> match v.Build with 0 -> () | _ -> $".0.%d{v.Build}" | ||||
|     | _ -> | ||||
|         sprintf ".%d" v.Minor | ||||
|         match v.Build with 0 -> () | _ -> sprintf ".%d" v.Build | ||||
|         $".%d{v.Minor}" | ||||
|         match v.Build with 0 -> () | _ -> $".%d{v.Build}" | ||||
|     } | ||||
|   |> String.concat "" | ||||
| #endif | ||||
|  | ||||
| @ -121,7 +121,7 @@ type UserCookie = | ||||
| 
 | ||||
| /// Create a salted hash to use to validate the idle timeout key | ||||
| let saltedTimeoutHash (c : TimeoutCookie) = | ||||
|   sha1Hash (sprintf "Prayer%ATracker%AIdle%dTimeout" c.Id c.GroupId c.Until) | ||||
|   sha1Hash $"Prayer%A{c.Id}Tracker%A{c.GroupId}Idle%d{c.Until}Timeout" | ||||
| 
 | ||||
| /// Cookie options to push an expiration out by 100 days | ||||
| let autoRefresh = | ||||
|  | ||||
| @ -32,9 +32,9 @@ let createMessage (grp : SmallGroup) subj = | ||||
| /// Create an HTML-format e-mail message | ||||
| let createHtmlMessage grp subj body (s : IStringLocalizer) = | ||||
|   let bodyText = | ||||
|     [ @"<!DOCTYPE html><html xmlns=""http://www.w3.org/1999/xhtml""><head><title></title></head><body>" | ||||
|     [ """<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><title></title></head><body>""" | ||||
|       body | ||||
|       @"<hr><div style=""text-align:right;font-family:Arial,Helvetica,sans-serif;font-size:8pt;padding-right:10px;"">" | ||||
|       """<hr><div style="text-align:right;font-family:Arial,Helvetica,sans-serif;font-size:8pt;padding-right:10px;">""" | ||||
|       s.["Generated by P R A Y E R T R A C K E R"].Value | ||||
|       "<br><small>" | ||||
|       s.["from Bit Badger Solutions"].Value | ||||
|  | ||||
| @ -35,7 +35,7 @@ let language culture : HttpHandler = | ||||
|       | "" | ||||
|       | "en" -> "en-US" | ||||
|       | "es" -> "es-MX" | ||||
|       | _ -> sprintf "%s-%s" culture (culture.ToUpper ()) | ||||
|       | _ -> $"{culture}-{culture.ToUpper ()}" | ||||
|       |> (CultureInfo >> Option.ofObj) | ||||
|     with | ||||
|     | :? CultureNotFoundException | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk.Web"> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
| @ -34,8 +34,4 @@ | ||||
|     <ProjectReference Include="..\PrayerTracker.UI\PrayerTracker.UI.fsproj" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <PackageReference Update="FSharp.Core" Version="4.7.0" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
| </Project> | ||||
|  | ||||
| @ -157,7 +157,7 @@ let logOnSubmit : HttpHandler = | ||||
|             return! redirectTo false "/web/prayer-requests/view" next ctx | ||||
|         | None -> | ||||
|             addError ctx s.["Password incorrect - login unsuccessful"] | ||||
|             return! redirectTo false (sprintf "/web/small-group/log-on/%s" (flatGuid m.smallGroupId)) next ctx | ||||
|             return! redirectTo false $"/web/small-group/log-on/{flatGuid m.smallGroupId}" next ctx | ||||
|       | Error e -> return! bindError e next ctx | ||||
|       } | ||||
| 
 | ||||
| @ -352,7 +352,7 @@ let sendAnnouncement : HttpHandler = | ||||
|           // Reformat the text to use the class's font stylings | ||||
|           let requestText = ckEditorToText m.text | ||||
|           let htmlText = | ||||
|             p [ _style (sprintf "font-family:%s;font-size:%dpt;" grp.preferences.listFonts grp.preferences.textFontSize) ] | ||||
|             p [ _style $"font-family:{grp.preferences.listFonts};font-size:%d{grp.preferences.textFontSize}pt;" ] | ||||
|               [ rawText requestText ] | ||||
|             |> renderHtmlNode | ||||
|           let plainText = (htmlToPlainText >> wordWrap 74) htmlText | ||||
|  | ||||
| @ -262,7 +262,7 @@ let save : HttpHandler = | ||||
|                         |> Some | ||||
|                     } | ||||
|                   |> addUserMessage ctx | ||||
|                   return! redirectTo false (sprintf "/web/user/%s/small-groups" (flatGuid u.userId)) next ctx | ||||
|                   return! redirectTo false $"/web/user/{flatGuid u.userId}/small-groups" next ctx | ||||
|               | false -> | ||||
|                   addInfo ctx s.["Successfully {0} user", s.["Updated"].Value.ToLower ()] | ||||
|                   return! redirectTo false "/web/users" next ctx | ||||
| @ -283,7 +283,7 @@ let saveGroups : HttpHandler = | ||||
|           match Seq.length m.smallGroups with | ||||
|           | 0 -> | ||||
|               addError ctx s.["You must select at least one group to assign"] | ||||
|               return! redirectTo false (sprintf "/web/user/%s/small-groups" (flatGuid m.userId)) next ctx | ||||
|               return! redirectTo false $"/web/user/{flatGuid m.userId}/small-groups" next ctx | ||||
|           | _ -> | ||||
|               let db = ctx.dbContext () | ||||
|               match! db.TryUserByIdWithGroups m.userId with | ||||
|  | ||||
							
								
								
									
										3
									
								
								src/Publish-App.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/Publish-App.ps1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| Set-Location PrayerTracker | ||||
| dotnet publish -c Release -r linux-x64 -p:PublishSingleFile=true --self-contained false | ||||
| Set-Location bin\Release\net5.0\linux-x64\publish | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user