Version 8 #43

Merged
danieljsummers merged 37 commits from version-8 into main 2022-08-19 19:08:31 +00:00
8 changed files with 67 additions and 46 deletions
Showing only changes of commit cd97f78a3e - Show all commits

View File

@ -375,7 +375,6 @@ type ChurchStats =
(*-- ENTITIES --*)
open System.Collections.Generic
open FSharp.EFCore.OptionConverter
open Microsoft.EntityFrameworkCore
open NodaTime
@ -401,7 +400,7 @@ type [<CLIMutable; NoComparison; NoEquality>] Church =
InterfaceAddress : string option
/// Small groups for this church
SmallGroups : ICollection<SmallGroup>
SmallGroups : ResizeArray<SmallGroup>
}
with
/// An empty church
@ -413,7 +412,7 @@ with
State = ""
HasVpsInterface = false
InterfaceAddress = None
SmallGroups = List<SmallGroup> ()
SmallGroups = ResizeArray<SmallGroup> ()
}
/// Configure EF for this entity
@ -430,9 +429,9 @@ with
} |> List.ofSeq |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<Church>).FindProperty(nameof Church.empty.Id)
.SetValueConverter(Converters.ChurchIdConverter ())
.SetValueConverter (Converters.ChurchIdConverter ())
mb.Model.FindEntityType(typeof<Church>).FindProperty(nameof Church.empty.InterfaceAddress)
.SetValueConverter(OptionConverter<string> ())
.SetValueConverter (OptionConverter<string> ())
/// Preferences for the form and format of the prayer request list
@ -556,15 +555,15 @@ with
} |> List.ofSeq |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.SmallGroupId)
.SetValueConverter(Converters.SmallGroupIdConverter ())
.SetValueConverter (Converters.SmallGroupIdConverter ())
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.RequestSort)
.SetValueConverter(Converters.RequestSortConverter ())
.SetValueConverter (Converters.RequestSortConverter ())
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.DefaultEmailType)
.SetValueConverter(Converters.EmailFormatConverter ())
.SetValueConverter (Converters.EmailFormatConverter ())
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.TimeZoneId)
.SetValueConverter(Converters.TimeZoneIdConverter ())
.SetValueConverter (Converters.TimeZoneIdConverter ())
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.AsOfDateDisplay)
.SetValueConverter(Converters.AsOfDateDisplayConverter ())
.SetValueConverter (Converters.AsOfDateDisplayConverter ())
/// A member of a small group
@ -612,11 +611,11 @@ with
} |> List.ofSeq |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<Member>).FindProperty(nameof Member.empty.Id)
.SetValueConverter(Converters.MemberIdConverter ())
.SetValueConverter (Converters.MemberIdConverter ())
mb.Model.FindEntityType(typeof<Member>).FindProperty(nameof Member.empty.SmallGroupId)
.SetValueConverter(Converters.SmallGroupIdConverter ())
.SetValueConverter (Converters.SmallGroupIdConverter ())
mb.Model.FindEntityType(typeof<Member>).FindProperty(nameof Member.empty.Format)
.SetValueConverter(Converters.EmailFormatOptionConverter ())
.SetValueConverter (Converters.EmailFormatOptionConverter ())
/// This represents a single prayer request
@ -707,17 +706,17 @@ with
} |> List.ofSeq |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.Id)
.SetValueConverter(Converters.PrayerRequestIdConverter ())
.SetValueConverter (Converters.PrayerRequestIdConverter ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.RequestType)
.SetValueConverter(Converters.PrayerRequestTypeConverter ())
.SetValueConverter (Converters.PrayerRequestTypeConverter ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.UserId)
.SetValueConverter(Converters.UserIdConverter ())
.SetValueConverter (Converters.UserIdConverter ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.SmallGroupId)
.SetValueConverter(Converters.SmallGroupIdConverter ())
.SetValueConverter (Converters.SmallGroupIdConverter ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.Requestor)
.SetValueConverter(OptionConverter<string> ())
.SetValueConverter (OptionConverter<string> ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.Expiration)
.SetValueConverter(Converters.ExpirationConverter ())
.SetValueConverter (Converters.ExpirationConverter ())
/// This represents a small group (Sunday School class, Bible study group, etc.)
@ -738,13 +737,13 @@ and [<CLIMutable; NoComparison; NoEquality>] SmallGroup =
Preferences : ListPreferences
/// The members of the group
Members : ICollection<Member>
Members : ResizeArray<Member>
/// Prayer requests for this small group
PrayerRequests : ICollection<PrayerRequest>
PrayerRequests : ResizeArray<PrayerRequest>
/// The users authorized to manage this group
Users : ICollection<UserSmallGroup>
Users : ResizeArray<UserSmallGroup>
}
with
@ -755,9 +754,9 @@ with
Name = ""
Church = Church.empty
Preferences = ListPreferences.empty
Members = List<Member> ()
PrayerRequests = List<PrayerRequest> ()
Users = List<UserSmallGroup> ()
Members = ResizeArray<Member> ()
PrayerRequests = ResizeArray<PrayerRequest> ()
Users = ResizeArray<UserSmallGroup> ()
}
/// Get the local date for this group
@ -788,9 +787,9 @@ with
} |> List.ofSeq |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<SmallGroup>).FindProperty(nameof SmallGroup.empty.Id)
.SetValueConverter(Converters.SmallGroupIdConverter ())
.SetValueConverter (Converters.SmallGroupIdConverter ())
mb.Model.FindEntityType(typeof<SmallGroup>).FindProperty(nameof SmallGroup.empty.ChurchId)
.SetValueConverter(Converters.ChurchIdConverter ())
.SetValueConverter (Converters.ChurchIdConverter ())
/// This represents a time zone in which a class may reside
@ -829,7 +828,7 @@ with
} |> List.ofSeq |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<TimeZone>).FindProperty(nameof TimeZone.empty.Id)
.SetValueConverter(Converters.TimeZoneIdConverter ())
.SetValueConverter (Converters.TimeZoneIdConverter ())
/// This represents a user of PrayerTracker
@ -855,8 +854,11 @@ and [<CLIMutable; NoComparison; NoEquality>] User =
/// The salt for the user's hashed password
Salt : Guid option
/// The last time the user was seen (set whenever the user is loaded into a session)
LastSeen : DateTime option
/// The small groups which this user is authorized
SmallGroups : ICollection<UserSmallGroup>
SmallGroups : ResizeArray<UserSmallGroup>
}
with
@ -869,7 +871,8 @@ with
IsAdmin = false
PasswordHash = ""
Salt = None
SmallGroups = List<UserSmallGroup> ()
LastSeen = None
SmallGroups = ResizeArray<UserSmallGroup> ()
}
/// The full name of the user
@ -889,12 +892,15 @@ with
it.Property(fun u -> u.IsAdmin).HasColumnName "is_admin"
it.Property(fun u -> u.PasswordHash).HasColumnName("password_hash").IsRequired ()
it.Property(fun u -> u.Salt).HasColumnName "salt"
it.Property(fun u -> u.LastSeen).HasColumnName "last_seen"
} |> List.ofSeq |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<User>).FindProperty(nameof User.empty.Id)
.SetValueConverter(Converters.UserIdConverter ())
.SetValueConverter (Converters.UserIdConverter ())
mb.Model.FindEntityType(typeof<User>).FindProperty(nameof User.empty.Salt)
.SetValueConverter(OptionConverter<Guid> ())
.SetValueConverter (OptionConverter<Guid> ())
mb.Model.FindEntityType(typeof<User>).FindProperty(nameof User.empty.LastSeen)
.SetValueConverter (OptionConverter<DateTime> ())
/// Cross-reference between user and small group
@ -930,15 +936,15 @@ with
it.Property(fun usg -> usg.UserId).HasColumnName "user_id"
it.Property(fun usg -> usg.SmallGroupId).HasColumnName "small_group_id"
it.HasOne(fun usg -> usg.User)
.WithMany(fun u -> u.SmallGroups :> IEnumerable<UserSmallGroup>)
.WithMany(fun u -> u.SmallGroups :> seq<UserSmallGroup>)
.HasForeignKey(fun usg -> usg.UserId :> obj)
it.HasOne(fun usg -> usg.SmallGroup)
.WithMany(fun sg -> sg.Users :> IEnumerable<UserSmallGroup>)
.WithMany(fun sg -> sg.Users :> seq<UserSmallGroup>)
.HasForeignKey(fun usg -> usg.SmallGroupId :> obj)
} |> List.ofSeq |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<UserSmallGroup>).FindProperty(nameof UserSmallGroup.empty.UserId)
.SetValueConverter(Converters.UserIdConverter ())
.SetValueConverter (Converters.UserIdConverter ())
mb.Model.FindEntityType(typeof<UserSmallGroup>).FindProperty(nameof UserSmallGroup.empty.SmallGroupId)
.SetValueConverter(Converters.SmallGroupIdConverter ())
.SetValueConverter (Converters.SmallGroupIdConverter ())

View File

@ -48,13 +48,14 @@ type InitialDatabase () =
name = "pt_user",
schema = "pt",
columns = (fun table ->
{| Id = table.Column<Guid> (name = "id", nullable = false)
Email = table.Column<string> (name = "email", nullable = false)
FirstName = table.Column<string> (name = "first_name", nullable = false)
IsAdmin = table.Column<bool> (name = "is_admin", nullable = false)
LastName = table.Column<string> (name = "last_name", nullable = false)
PasswordHash = table.Column<string> (name = "password_hash", nullable = false)
Salt = table.Column<Guid> (name = "salt", nullable = true)
{| Id = table.Column<Guid> (name = "id", nullable = false)
Email = table.Column<string> (name = "email", nullable = false)
FirstName = table.Column<string> (name = "first_name", nullable = false)
IsAdmin = table.Column<bool> (name = "is_admin", nullable = false)
LastName = table.Column<string> (name = "last_name", nullable = false)
PasswordHash = table.Column<string> (name = "password_hash", nullable = false)
Salt = table.Column<Guid> (name = "salt", nullable = true)
LastSeen = table.Column<DateTime> (name = "last_seen", nullable = true)
|}),
constraints = fun table ->
table.PrimaryKey("pk_pt_user", fun x -> upcast x.Id) |> ignore)
@ -321,6 +322,7 @@ type InitialDatabase () =
b.Property<string>("LastName").HasColumnName("last_name").IsRequired() |> ignore
b.Property<string>("PasswordHash").HasColumnName("password_hash").IsRequired() |> ignore
b.Property<Guid>("Salt").HasColumnName("salt") |> ignore
b.Property<DateTime>("LastSeen").HasColumnName("last_seen") |> ignore
b.HasKey("Id") |> ignore
b.ToTable("pt_user") |> ignore)
|> ignore

View File

@ -106,6 +106,7 @@ type AppDbContextModelSnapshot () =
b.Property<string>("LastName").HasColumnName("last_name").IsRequired() |> ignore
b.Property<string>("PasswordHash").HasColumnName("password_hash").IsRequired() |> ignore
b.Property<Guid>("Salt").HasColumnName("salt") |> ignore
b.Property<DateTime>("LastSeen").HasColumnName("last_seen") |> ignore
b.HasKey("Id") |> ignore
b.ToTable("pt_user") |> ignore)
|> ignore

View File

@ -825,4 +825,7 @@
<data name="State or Province" xml:space="preserve">
<value>Estado o Provincia</value>
</data>
<data name="Last Seen" xml:space="preserve">
<value>Ultima vez Visto</value>
</data>
</root>

View File

@ -192,7 +192,7 @@ let maintain (users : User list) ctx viewInfo =
| [] -> space
| _ ->
table [ _class "pt-table pt-action-table" ] [
tableHeadings s [ "Actions"; "Name"; "Admin?" ]
tableHeadings s [ "Actions"; "Name"; "Last Seen"; "Admin?" ]
users
|> List.map (fun user ->
let userId = shortGuid user.Id.Value
@ -212,6 +212,9 @@ let maintain (users : User list) ctx viewInfo =
]
]
td [] [ str user.Name ]
td [] [
str (match user.LastSeen with Some dt -> dt.ToString s["MMMM d, yyyy"] | None -> "--")
]
td [ _class "pt-center-text" ] [
if user.IsAdmin then strong [] [ locStr s["Yes"] ] else locStr s["No"]
]

View File

@ -1,6 +1,7 @@
[<AutoOpen>]
module PrayerTracker.Extensions
open System
open Microsoft.AspNetCore.Http
open Microsoft.FSharpLu
open Newtonsoft.Json
@ -98,7 +99,11 @@ type HttpContext with
| Some userId ->
match! this.Db.TryUserById userId with
| Some user ->
this.Session.CurrentUser <- Some user
// 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<UserSmallGroup> () }
return Some user
| None -> return None
| None -> return None

View File

@ -94,6 +94,7 @@ ALTER TABLE pt."User" RENAME COLUMN "PasswordHash" TO password_hash;
ALTER TABLE pt."User" RENAME COLUMN "Salt" TO salt;
ALTER TABLE pt."User" RENAME CONSTRAINT "PK_User" TO pk_pt_user;
ALTER TABLE pt."User" RENAME TO pt_user;
ALTER TABLE pt.pt_user ADD COLUMN last_seen timestamp;
-- User / Small Group
ALTER TABLE pt."User_SmallGroup" RENAME COLUMN "UserId" TO user_id;