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…
Reference in New Issue
Block a user