diff --git a/src/PrayerTracker.UI/Layout.fs b/src/PrayerTracker.UI/Layout.fs index a193cca..368259e 100644 --- a/src/PrayerTracker.UI/Layout.fs +++ b/src/PrayerTracker.UI/Layout.fs @@ -234,25 +234,25 @@ let private renderPageTitle viewInfo pgTitle = /// Render the messages that may need to be displayed to the user let private messages viewInfo = let s = I18N.localizer.Force () - viewInfo.Messages - |> List.map (fun msg -> - table [ _class $"pt-msg {MessageLevel.toCssClass msg.Level}" ] [ - tr [] [ - td [] [ - match msg.Level with - | Info -> () - | lvl -> - strong [] [ locStr s[MessageLevel.toString lvl] ] - rawText " » " - rawText msg.Text.Value - match msg.Description with - | Some desc -> - br [] - div [ _class "description" ] [ rawText desc.Value ] - | None -> () - ] - ] - ]) + if List.isEmpty viewInfo.Messages then [] + else + viewInfo.Messages + |> List.map (fun msg -> + div [ _class $"pt-msg {MessageLevel.toCssClass msg.Level}" ] [ + match msg.Level with + | Info -> () + | lvl -> + strong [] [ locStr s[MessageLevel.toString lvl] ] + rawText " » " + rawText msg.Text.Value + match msg.Description with + | Some desc -> + br [] + div [ _class "description" ] [ rawText desc.Value ] + | None -> () + ]) + |> div [ _class "pt-messages" ] + |> List.singleton open System diff --git a/src/PrayerTracker/Extensions.fs b/src/PrayerTracker/Extensions.fs index 72063c0..665d344 100644 --- a/src/PrayerTracker/Extensions.fs +++ b/src/PrayerTracker/Extensions.fs @@ -32,7 +32,8 @@ type ISession with with get () = this.GetObject Key.Session.currentUser |> Option.fromObject and set (v : User option) = match v with - | Some user -> this.SetObject Key.Session.currentUser user + | Some user -> + this.SetObject Key.Session.currentUser { user with PasswordHash = ""; SmallGroups = ResizeArray() } | None -> this.Remove Key.Session.currentUser /// Current messages for the session @@ -102,8 +103,7 @@ type HttpContext with // Set last seen for user this.Db.UpdateEntry { user with LastSeen = Some DateTime.UtcNow } let! _ = this.Db.SaveChangesAsync () - this.Session.CurrentUser <- - Some { user with PasswordHash = ""; SmallGroups = ResizeArray () } + this.Session.CurrentUser <- Some user return Some user | None -> return None | None -> return None diff --git a/src/PrayerTracker/User.fs b/src/PrayerTracker/User.fs index a130317..df9a73c 100644 --- a/src/PrayerTracker/User.fs +++ b/src/PrayerTracker/User.fs @@ -53,16 +53,16 @@ module Hashing = /// Retrieve a user from the database by password, upgrading password hashes if required let private findUserByPassword model (db : AppDbContext) = task { - let bareUser user = Some { user with PasswordHash = ""; SmallGroups = ResizeArray() } match! db.TryUserByEmailAndGroup model.Email (idFromShort SmallGroupId model.SmallGroupId) with | Some user -> let hasher = PrayerTrackerPasswordHasher () match hasher.VerifyHashedPassword (user, user.PasswordHash, model.Password) with - | PasswordVerificationResult.Success -> return bareUser user + | PasswordVerificationResult.Success -> return Some user | PasswordVerificationResult.SuccessRehashNeeded -> - db.UpdateEntry { user with PasswordHash = hasher.HashPassword (user, model.Password) } + let upgraded = { user with PasswordHash = hasher.HashPassword (user, model.Password) } + db.UpdateEntry upgraded let! _ = db.SaveChangesAsync () - return bareUser user + return Some upgraded | _ -> return None | None -> return None } @@ -145,6 +145,8 @@ let doLogOn : HttpHandler = requireAccess [ AccessLevel.Public ] >=> validateCsr AuthenticationProperties ( IssuedUtc = DateTimeOffset.UtcNow, IsPersistent = defaultArg model.RememberMe false)) + ctx.Db.UpdateEntry { user with LastSeen = Some DateTime.UtcNow } + let! _ = ctx.Db.SaveChangesAsync () addHtmlInfo ctx s["Log On Successful • Welcome to {0}", s["PrayerTracker"]] return! redirectTo false (sanitizeUrl model.RedirectUrl "/small-group") next ctx | None -> return! fourOhFour ctx diff --git a/src/PrayerTracker/wwwroot/css/app.css b/src/PrayerTracker/wwwroot/css/app.css index 43d35cb..3172cdc 100644 --- a/src/PrayerTracker/wwwroot/css/app.css +++ b/src/PrayerTracker/wwwroot/css/app.css @@ -266,31 +266,35 @@ footer a:hover { margin: auto; border-collapse: collapse; } -.pt-table tr:hover { +.pt-table thead { + background-image: linear-gradient(to bottom, var(--dark), var(--lighter-dark)); + color: white; +} +.pt-table tbody tr:hover { background-color: #eee; } .pt-table tr th, .pt-table tr td { padding: .25rem .5rem; } -.pt-table tr td { - border-bottom: dotted 1px #444; +.pt-table tbody tr td { + border-bottom: solid 1px var(--lighter-dark); } -.pt-action-table tr td:first-child { +.pt-action-table tbody tr td:first-child { white-space: nowrap; border-bottom: 0; } -.pt-action-table tr td:first-child a { - background-color: lightgray; +.pt-action-table tbody tr td:first-child a { + background-color: gray; color: white; border-radius: .5rem; padding: .125rem .5rem .5rem .5rem; margin: 0 .125rem; } -.pt-action-table tr:hover td:first-child a { - background-color: navy; +.pt-action-table tbody tr:hover td:first-child a { + background-color: var(--dark); } -.pt-action-table tr td:first-child a:hover { +.pt-action-table tbody tr td:first-child a:hover { border-bottom: 0; } /* TODO: Figure out nice CSS transitions for these; these don't work */ @@ -339,6 +343,12 @@ article.pt-overview section div p { .pt-editor { width: 100%; } +.pt-messages { + display: flex; + flex-flow: column; + justify-content: center; + align-items: center; +} .pt-msg { margin: .5rem auto; border-top-right-radius: .5rem; @@ -346,15 +356,12 @@ article.pt-overview section div p { border-width: 2px; border-style: solid; border-collapse: inherit; + padding: 5px 30px; + text-align: center; } .pt-msg ul { text-align: left; } -.pt-msg td { - padding: 5px 30px; - margin-bottom: 2px; - text-align: center; -} .pt-msg.error { background-color: #ffb6c1; border-color: #ff0000;