Update last seen on log on (#39)

- Tweak table styles (#38)
This commit is contained in:
Daniel J. Summers 2022-08-05 22:36:29 -04:00
parent cd97f78a3e
commit 539e20ae87
4 changed files with 49 additions and 40 deletions

View File

@ -234,25 +234,25 @@ let private renderPageTitle viewInfo pgTitle =
/// Render the messages that may need to be displayed to the user /// Render the messages that may need to be displayed to the user
let private messages viewInfo = let private messages viewInfo =
let s = I18N.localizer.Force () let s = I18N.localizer.Force ()
viewInfo.Messages if List.isEmpty viewInfo.Messages then []
|> List.map (fun msg -> else
table [ _class $"pt-msg {MessageLevel.toCssClass msg.Level}" ] [ viewInfo.Messages
tr [] [ |> List.map (fun msg ->
td [] [ div [ _class $"pt-msg {MessageLevel.toCssClass msg.Level}" ] [
match msg.Level with match msg.Level with
| Info -> () | Info -> ()
| lvl -> | lvl ->
strong [] [ locStr s[MessageLevel.toString lvl] ] strong [] [ locStr s[MessageLevel.toString lvl] ]
rawText " » " rawText " » "
rawText msg.Text.Value rawText msg.Text.Value
match msg.Description with match msg.Description with
| Some desc -> | Some desc ->
br [] br []
div [ _class "description" ] [ rawText desc.Value ] div [ _class "description" ] [ rawText desc.Value ]
| None -> () | None -> ()
] ])
] |> div [ _class "pt-messages" ]
]) |> List.singleton
open System open System

View File

@ -32,7 +32,8 @@ type ISession with
with get () = this.GetObject<User> Key.Session.currentUser |> Option.fromObject with get () = this.GetObject<User> Key.Session.currentUser |> Option.fromObject
and set (v : User option) = and set (v : User option) =
match v with 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 | None -> this.Remove Key.Session.currentUser
/// Current messages for the session /// Current messages for the session
@ -102,8 +103,7 @@ type HttpContext with
// Set last seen for user // Set last seen for user
this.Db.UpdateEntry { user with LastSeen = Some DateTime.UtcNow } this.Db.UpdateEntry { user with LastSeen = Some DateTime.UtcNow }
let! _ = this.Db.SaveChangesAsync () let! _ = this.Db.SaveChangesAsync ()
this.Session.CurrentUser <- this.Session.CurrentUser <- Some user
Some { user with PasswordHash = ""; SmallGroups = ResizeArray<UserSmallGroup> () }
return Some user return Some user
| None -> return None | None -> return None
| None -> return None | None -> return None

View File

@ -53,16 +53,16 @@ module Hashing =
/// Retrieve a user from the database by password, upgrading password hashes if required /// Retrieve a user from the database by password, upgrading password hashes if required
let private findUserByPassword model (db : AppDbContext) = task { let private findUserByPassword model (db : AppDbContext) = task {
let bareUser user = Some { user with PasswordHash = ""; SmallGroups = ResizeArray<UserSmallGroup>() }
match! db.TryUserByEmailAndGroup model.Email (idFromShort SmallGroupId model.SmallGroupId) with match! db.TryUserByEmailAndGroup model.Email (idFromShort SmallGroupId model.SmallGroupId) with
| Some user -> | Some user ->
let hasher = PrayerTrackerPasswordHasher () let hasher = PrayerTrackerPasswordHasher ()
match hasher.VerifyHashedPassword (user, user.PasswordHash, model.Password) with match hasher.VerifyHashedPassword (user, user.PasswordHash, model.Password) with
| PasswordVerificationResult.Success -> return bareUser user | PasswordVerificationResult.Success -> return Some user
| PasswordVerificationResult.SuccessRehashNeeded -> | 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 () let! _ = db.SaveChangesAsync ()
return bareUser user return Some upgraded
| _ -> return None | _ -> return None
| None -> return None | None -> return None
} }
@ -145,6 +145,8 @@ let doLogOn : HttpHandler = requireAccess [ AccessLevel.Public ] >=> validateCsr
AuthenticationProperties ( AuthenticationProperties (
IssuedUtc = DateTimeOffset.UtcNow, IssuedUtc = DateTimeOffset.UtcNow,
IsPersistent = defaultArg model.RememberMe false)) 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"]] addHtmlInfo ctx s["Log On Successful Welcome to {0}", s["PrayerTracker"]]
return! redirectTo false (sanitizeUrl model.RedirectUrl "/small-group") next ctx return! redirectTo false (sanitizeUrl model.RedirectUrl "/small-group") next ctx
| None -> return! fourOhFour ctx | None -> return! fourOhFour ctx

View File

@ -266,31 +266,35 @@ footer a:hover {
margin: auto; margin: auto;
border-collapse: collapse; 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; background-color: #eee;
} }
.pt-table tr th, .pt-table tr th,
.pt-table tr td { .pt-table tr td {
padding: .25rem .5rem; padding: .25rem .5rem;
} }
.pt-table tr td { .pt-table tbody tr td {
border-bottom: dotted 1px #444; 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; white-space: nowrap;
border-bottom: 0; border-bottom: 0;
} }
.pt-action-table tr td:first-child a { .pt-action-table tbody tr td:first-child a {
background-color: lightgray; background-color: gray;
color: white; color: white;
border-radius: .5rem; border-radius: .5rem;
padding: .125rem .5rem .5rem .5rem; padding: .125rem .5rem .5rem .5rem;
margin: 0 .125rem; margin: 0 .125rem;
} }
.pt-action-table tr:hover td:first-child a { .pt-action-table tbody tr:hover td:first-child a {
background-color: navy; 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; border-bottom: 0;
} }
/* TODO: Figure out nice CSS transitions for these; these don't work */ /* TODO: Figure out nice CSS transitions for these; these don't work */
@ -339,6 +343,12 @@ article.pt-overview section div p {
.pt-editor { .pt-editor {
width: 100%; width: 100%;
} }
.pt-messages {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
}
.pt-msg { .pt-msg {
margin: .5rem auto; margin: .5rem auto;
border-top-right-radius: .5rem; border-top-right-radius: .5rem;
@ -346,15 +356,12 @@ article.pt-overview section div p {
border-width: 2px; border-width: 2px;
border-style: solid; border-style: solid;
border-collapse: inherit; border-collapse: inherit;
padding: 5px 30px;
text-align: center;
} }
.pt-msg ul { .pt-msg ul {
text-align: left; text-align: left;
} }
.pt-msg td {
padding: 5px 30px;
margin-bottom: 2px;
text-align: center;
}
.pt-msg.error { .pt-msg.error {
background-color: #ffb6c1; background-color: #ffb6c1;
border-color: #ff0000; border-color: #ff0000;