diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 2f20663..47fecfd 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,9 +1,9 @@ - 7.4.2.0 - 7.4.2.0 + 7.5.0.0 + 7.5.0.0 danieljsummers Bit Badger Solutions - 7.4.2 + 7.5.0 diff --git a/src/PrayerTracker.Data/DataAccess.fs b/src/PrayerTracker.Data/DataAccess.fs index d36f0cb..2dc2215 100644 --- a/src/PrayerTracker.Data/DataAccess.fs +++ b/src/PrayerTracker.Data/DataAccess.fs @@ -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 } diff --git a/src/PrayerTracker.Data/PrayerTracker.Data.fsproj b/src/PrayerTracker.Data/PrayerTracker.Data.fsproj index 1d7816f..b00699a 100644 --- a/src/PrayerTracker.Data/PrayerTracker.Data.fsproj +++ b/src/PrayerTracker.Data/PrayerTracker.Data.fsproj @@ -1,7 +1,7 @@  - netstandard2.1 + net5.0 @@ -20,8 +20,4 @@ - - - - diff --git a/src/PrayerTracker.Tests/PrayerTracker.Tests.fsproj b/src/PrayerTracker.Tests/PrayerTracker.Tests.fsproj index 5fc7eea..ebe2fbf 100644 --- a/src/PrayerTracker.Tests/PrayerTracker.Tests.fsproj +++ b/src/PrayerTracker.Tests/PrayerTracker.Tests.fsproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net5.0 @@ -26,8 +26,4 @@ - - - - diff --git a/src/PrayerTracker.UI/Church.fs b/src/PrayerTracker.UI/Church.fs index 8e2f317..167390c 100644 --- a/src/PrayerTracker.UI/Church.fs +++ b/src/PrayerTracker.UI/Church.fs @@ -74,15 +74,15 @@ let maintain (churches : Church list) (stats : Map) 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) 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 [] diff --git a/src/PrayerTracker.UI/CommonFunctions.fs b/src/PrayerTracker.UI/CommonFunctions.fs index d89fb7c..9fa8aea 100644 --- a/src/PrayerTracker.UI/CommonFunctions.fs +++ b/src/PrayerTracker.UI/CommonFunctions.fs @@ -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 diff --git a/src/PrayerTracker.UI/Home.fs b/src/PrayerTracker.UI/Home.fs index 65edce0..2ad9fda 100644 --- a/src/PrayerTracker.UI/Home.fs +++ b/src/PrayerTracker.UI/Home.fs @@ -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 ] diff --git a/src/PrayerTracker.UI/I18N.fs b/src/PrayerTracker.UI/I18N.fs index 8e6ddbe..7360e0a 100644 --- a/src/PrayerTracker.UI/I18N.fs +++ b/src/PrayerTracker.UI/I18N.fs @@ -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) diff --git a/src/PrayerTracker.UI/Layout.fs b/src/PrayerTracker.UI/Layout.fs index b692840..1b9c558 100644 --- a/src/PrayerTracker.UI/Layout.fs +++ b/src/PrayerTracker.UI/Layout.fs @@ -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 diff --git a/src/PrayerTracker.UI/PrayerRequest.fs b/src/PrayerTracker.UI/PrayerRequest.fs index b619d71..60550d5 100644 --- a/src/PrayerTracker.UI/PrayerRequest.fs +++ b/src/PrayerTracker.UI/PrayerRequest.fs @@ -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 diff --git a/src/PrayerTracker.UI/PrayerTracker.UI.fsproj b/src/PrayerTracker.UI/PrayerTracker.UI.fsproj index 55d7598..fb49b75 100644 --- a/src/PrayerTracker.UI/PrayerTracker.UI.fsproj +++ b/src/PrayerTracker.UI/PrayerTracker.UI.fsproj @@ -1,7 +1,7 @@  - netstandard2.1 + net5.0 @@ -61,8 +61,4 @@ - - - - diff --git a/src/PrayerTracker.UI/SmallGroup.fs b/src/PrayerTracker.UI/SmallGroup.fs index cdd279f..068dd6d 100644 --- a/src/PrayerTracker.UI/SmallGroup.fs +++ b/src/PrayerTracker.UI/SmallGroup.fs @@ -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) 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) 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 [] diff --git a/src/PrayerTracker.UI/User.fs b/src/PrayerTracker.UI/User.fs index 9f933cc..965d0f8 100644 --- a/src/PrayerTracker.UI/User.fs +++ b/src/PrayerTracker.UI/User.fs @@ -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 [] diff --git a/src/PrayerTracker.UI/Utils.fs b/src/PrayerTracker.UI/Utils.fs index b7c8766..87e48ad 100644 --- a/src/PrayerTracker.UI/Utils.fs +++ b/src/PrayerTracker.UI/Utils.fs @@ -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 "" = 0 + || htmlTag.IndexOf $"<{t} " = 0 + || htmlTag.IndexOf $" () | 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 () = diff --git a/src/PrayerTracker.UI/ViewModels.fs b/src/PrayerTracker.UI/ViewModels.fs index 518e758..52c8b24 100644 --- a/src/PrayerTracker.UI/ViewModels.fs +++ b/src/PrayerTracker.UI/ViewModels.fs @@ -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) " " } diff --git a/src/PrayerTracker/App.fs b/src/PrayerTracker/App.fs index ab186e3..0d1d00d 100644 --- a/src/PrayerTracker/App.fs +++ b/src/PrayerTracker/App.fs @@ -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 diff --git a/src/PrayerTracker/CommonFunctions.fs b/src/PrayerTracker/CommonFunctions.fs index eed53c7..00f5a46 100644 --- a/src/PrayerTracker/CommonFunctions.fs +++ b/src/PrayerTracker/CommonFunctions.fs @@ -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 diff --git a/src/PrayerTracker/Cookies.fs b/src/PrayerTracker/Cookies.fs index 4a8cdaf..6eca03f 100644 --- a/src/PrayerTracker/Cookies.fs +++ b/src/PrayerTracker/Cookies.fs @@ -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 = diff --git a/src/PrayerTracker/Email.fs b/src/PrayerTracker/Email.fs index 89f5d0d..87dc18c 100644 --- a/src/PrayerTracker/Email.fs +++ b/src/PrayerTracker/Email.fs @@ -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 = - [ @"" + [ """""" body - @"
" + """
""" s.["Generated by P R A Y E R T R A C K E R"].Value "
" s.["from Bit Badger Solutions"].Value diff --git a/src/PrayerTracker/Home.fs b/src/PrayerTracker/Home.fs index 804f199..4fe7a80 100644 --- a/src/PrayerTracker/Home.fs +++ b/src/PrayerTracker/Home.fs @@ -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 diff --git a/src/PrayerTracker/PrayerTracker.fsproj b/src/PrayerTracker/PrayerTracker.fsproj index 3b79b96..1cdc542 100644 --- a/src/PrayerTracker/PrayerTracker.fsproj +++ b/src/PrayerTracker/PrayerTracker.fsproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net5.0 @@ -34,8 +34,4 @@ - - - - diff --git a/src/PrayerTracker/SmallGroup.fs b/src/PrayerTracker/SmallGroup.fs index 59a6a92..77685ac 100644 --- a/src/PrayerTracker/SmallGroup.fs +++ b/src/PrayerTracker/SmallGroup.fs @@ -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 diff --git a/src/PrayerTracker/User.fs b/src/PrayerTracker/User.fs index aab2fd2..066d7f0 100644 --- a/src/PrayerTracker/User.fs +++ b/src/PrayerTracker/User.fs @@ -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 diff --git a/src/Publish-App.ps1 b/src/Publish-App.ps1 new file mode 100644 index 0000000..5222d90 --- /dev/null +++ b/src/Publish-App.ps1 @@ -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 \ No newline at end of file