Version 8 #43
| @ -231,7 +231,7 @@ type AppDbContext with | ||||
|         let! usr = this.Users.Include(fun u -> u.SmallGroups).SingleOrDefaultAsync (fun u -> u.Id = userId) | ||||
|         return Option.fromObject usr | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     /// Get a list of all users | ||||
|     member this.AllUsers () = backgroundTask { | ||||
|         let! users = this.Users.OrderBy(fun u -> u.LastName).ThenBy(fun u -> u.FirstName).ToListAsync () | ||||
|  | ||||
| @ -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 ()) | ||||
|          | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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> | ||||
| @ -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"] | ||||
|                         ] | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user