First cut of blue theme (#38)

- Fix onload scripts with htmx navigation (#36)
- Convert db to use identifiers that do not require quoting
This commit is contained in:
Daniel J. Summers 2022-08-03 14:36:00 -04:00
parent f068d20612
commit f6c483b7c0
19 changed files with 1167 additions and 1241 deletions

View File

@ -78,13 +78,13 @@ type AppDbContext (options : DbContextOptions<AppDbContext>) =
modelBuilder.HasDefaultSchema "pt" |> ignore modelBuilder.HasDefaultSchema "pt" |> ignore
[ Church.configureEF [ Church.ConfigureEF
ListPreferences.configureEF ListPreferences.ConfigureEF
Member.configureEF Member.ConfigureEF
PrayerRequest.configureEF PrayerRequest.ConfigureEF
SmallGroup.configureEF SmallGroup.ConfigureEF
TimeZone.configureEF TimeZone.ConfigureEF
User.configureEF User.ConfigureEF
UserSmallGroup.configureEF UserSmallGroup.ConfigureEF
] ]
|> List.iter (fun x -> x modelBuilder) |> List.iter (fun x -> x modelBuilder)

View File

@ -91,7 +91,7 @@ type AppDbContext with
/// Get all (or active) requests for a small group as of now or the specified date /// Get all (or active) requests for a small group as of now or the specified date
member this.AllRequestsForSmallGroup (grp : SmallGroup) clock listDate activeOnly pageNbr = backgroundTask { member this.AllRequestsForSmallGroup (grp : SmallGroup) clock listDate activeOnly pageNbr = backgroundTask {
let theDate = match listDate with Some dt -> dt | _ -> grp.localDateNow clock let theDate = match listDate with Some dt -> dt | _ -> grp.LocalDateNow clock
let query = let query =
this.PrayerRequests.Where(fun req -> req.SmallGroupId = grp.Id) this.PrayerRequests.Where(fun req -> req.SmallGroupId = grp.Id)
|> function |> function
@ -120,15 +120,15 @@ type AppDbContext with
return! this.PrayerRequests.CountAsync (fun pr -> pr.SmallGroup.ChurchId = churchId) return! this.PrayerRequests.CountAsync (fun pr -> pr.SmallGroup.ChurchId = churchId)
} }
/// Get all (or active) requests for a small group as of now or the specified date /// Search requests for a small group using the given case-insensitive search term
member this.SearchRequestsForSmallGroup (grp : SmallGroup) (searchTerm : string) pageNbr = backgroundTask { member this.SearchRequestsForSmallGroup (grp : SmallGroup) (searchTerm : string) pageNbr = backgroundTask {
let sql = """ let sql = """
SELECT * FROM pt."PrayerRequest" WHERE "SmallGroupId" = {0} AND "Text" ILIKE {1} SELECT * FROM pt.prayer_request WHERE small_group_id = {0} AND request_text ILIKE {1}
UNION UNION
SELECT * FROM pt."PrayerRequest" WHERE "SmallGroupId" = {0} AND COALESCE("Requestor", '') ILIKE {1}""" SELECT * FROM pt.prayer_request WHERE small_group_id = {0} AND COALESCE(requestor, '') ILIKE {1}"""
let like = sprintf "%%%s%%" let like = sprintf "%%%s%%"
let query = let query =
this.PrayerRequests.FromSqlRaw(sql, grp.Id, like searchTerm) this.PrayerRequests.FromSqlRaw (sql, grp.Id.Value, like searchTerm)
|> reqSort grp.Preferences.RequestSort |> reqSort grp.Preferences.RequestSort
|> paginate pageNbr grp.Preferences.PageSize |> paginate pageNbr grp.Preferences.PageSize
let! reqs = query.ToListAsync () let! reqs = query.ToListAsync ()
@ -255,7 +255,7 @@ type AppDbContext with
/// Get all PrayerTracker users as members (used to send e-mails) /// Get all PrayerTracker users as members (used to send e-mails)
member this.AllUsersAsMembers () = backgroundTask { member this.AllUsersAsMembers () = backgroundTask {
let! users = this.AllUsers () let! users = this.AllUsers ()
return users |> List.map (fun u -> { Member.empty with Email = u.Email; Name = u.fullName }) return users |> List.map (fun u -> { Member.empty with Email = u.Email; Name = u.Name })
} }
/// Find a user based on their credentials /// Find a user based on their credentials

View File

@ -394,8 +394,8 @@ type [<CLIMutable; NoComparison; NoEquality>] Church =
/// The 2-letter state or province code for the church's location /// The 2-letter state or province code for the church's location
State : string State : string
/// Does this church have an active interface with Virtual Prayer Room? /// Does this church have an active interface with Virtual Prayer Space?
HasInterface : bool HasVpsInterface : bool
/// The address for the interface /// The address for the interface
InterfaceAddress : string option InterfaceAddress : string option
@ -411,24 +411,27 @@ with
Name = "" Name = ""
City = "" City = ""
State = "" State = ""
HasInterface = false HasVpsInterface = false
InterfaceAddress = None InterfaceAddress = None
SmallGroups = List<SmallGroup> () SmallGroups = List<SmallGroup> ()
} }
/// Configure EF for this entity /// Configure EF for this entity
static member internal configureEF (mb : ModelBuilder) = static member internal ConfigureEF (mb : ModelBuilder) =
mb.Entity<Church> (fun m -> mb.Entity<Church> (fun it ->
m.ToTable "Church" |> ignore seq<obj> {
m.Property(fun e -> e.Id).HasColumnName "ChurchId" |> ignore it.ToTable "church"
m.Property(fun e -> e.Name).HasColumnName("Name").IsRequired () |> ignore it.Property(fun c -> c.Id).HasColumnName "id"
m.Property(fun e -> e.City).HasColumnName("City").IsRequired () |> ignore it.Property(fun c -> c.Name).HasColumnName("church_name").IsRequired ()
m.Property(fun e -> e.State).HasColumnName("ST").IsRequired().HasMaxLength 2 |> ignore it.Property(fun c -> c.City).HasColumnName("city").IsRequired ()
m.Property(fun e -> e.HasInterface).HasColumnName "HasVirtualPrayerRoomInterface" |> ignore it.Property(fun c -> c.State).HasColumnName("state").IsRequired().HasMaxLength 2
m.Property(fun e -> e.InterfaceAddress).HasColumnName "InterfaceAddress" |> ignore) it.Property(fun c -> c.HasVpsInterface).HasColumnName "has_vps_interface"
it.Property(fun c -> c.InterfaceAddress).HasColumnName "interface_address"
} |> List.ofSeq |> ignore)
|> ignore |> ignore
mb.Model.FindEntityType(typeof<Church>).FindProperty("Id").SetValueConverter(Converters.ChurchIdConverter ()) mb.Model.FindEntityType(typeof<Church>).FindProperty(nameof Church.empty.Id)
mb.Model.FindEntityType(typeof<Church>).FindProperty("InterfaceAddress") .SetValueConverter(Converters.ChurchIdConverter ())
mb.Model.FindEntityType(typeof<Church>).FindProperty(nameof Church.empty.InterfaceAddress)
.SetValueConverter(OptionConverter<string> ()) .SetValueConverter(OptionConverter<string> ())
@ -517,108 +520,50 @@ with
} }
/// Configure EF for this entity /// Configure EF for this entity
static member internal configureEF (mb : ModelBuilder) = static member internal ConfigureEF (mb : ModelBuilder) =
mb.Entity<ListPreferences> (fun m -> mb.Entity<ListPreferences> (fun it ->
m.ToTable "ListPreference" |> ignore seq<obj> {
m.HasKey (fun e -> e.SmallGroupId :> obj) |> ignore it.ToTable "list_preference"
m.Property(fun e -> e.SmallGroupId).HasColumnName "SmallGroupId" |> ignore it.HasKey (fun lp -> lp.SmallGroupId :> obj)
m.Property(fun e -> e.DaysToKeepNew) it.Property(fun lp -> lp.SmallGroupId).HasColumnName "small_group_id"
.HasColumnName("DaysToKeepNew") it.Property(fun lp -> lp.DaysToKeepNew).HasColumnName("days_to_keep_new").IsRequired().HasDefaultValue 7
.IsRequired() it.Property(fun lp -> lp.DaysToExpire).HasColumnName("days_to_expire").IsRequired().HasDefaultValue 14
.HasDefaultValue 7 it.Property(fun lp -> lp.LongTermUpdateWeeks).HasColumnName("long_term_update_weeks").IsRequired()
|> ignore .HasDefaultValue 4
m.Property(fun e -> e.DaysToExpire) it.Property(fun lp -> lp.EmailFromName).HasColumnName("email_from_name").IsRequired()
.HasColumnName("DaysToExpire") .HasDefaultValue "PrayerTracker"
.IsRequired() it.Property(fun lp -> lp.EmailFromAddress).HasColumnName("email_from_address").IsRequired()
.HasDefaultValue 14 .HasDefaultValue "prayer@djs-consulting.com"
|> ignore it.Property(fun lp -> lp.Fonts).HasColumnName("fonts").IsRequired()
m.Property(fun e -> e.LongTermUpdateWeeks) .HasDefaultValue "Century Gothic,Tahoma,Luxi Sans,sans-serif"
.HasColumnName("LongTermUpdateWeeks") it.Property(fun lp -> lp.HeadingColor).HasColumnName("heading_color").IsRequired()
.IsRequired() .HasDefaultValue "maroon"
.HasDefaultValue 4 it.Property(fun lp -> lp.LineColor).HasColumnName("line_color").IsRequired().HasDefaultValue "navy"
|> ignore it.Property(fun lp -> lp.HeadingFontSize).HasColumnName("heading_font_size").IsRequired()
m.Property(fun e -> e.EmailFromName) .HasDefaultValue 16
.HasColumnName("EmailFromName") it.Property(fun lp -> lp.TextFontSize).HasColumnName("text_font_size").IsRequired().HasDefaultValue 12
.IsRequired() it.Property(fun lp -> lp.RequestSort).HasColumnName("request_sort").IsRequired().HasMaxLength(1)
.HasDefaultValue "PrayerTracker" .HasDefaultValue SortByDate
|> ignore it.Property(fun lp -> lp.GroupPassword).HasColumnName("group_password").IsRequired().HasDefaultValue ""
m.Property(fun e -> e.EmailFromAddress) it.Property(fun lp -> lp.DefaultEmailType).HasColumnName("default_email_type").IsRequired()
.HasColumnName("EmailFromAddress") .HasDefaultValue HtmlFormat
.IsRequired() it.Property(fun lp -> lp.IsPublic).HasColumnName("is_public").IsRequired().HasDefaultValue false
.HasDefaultValue "prayer@djs-consulting.com" it.Property(fun lp -> lp.TimeZoneId).HasColumnName("time_zone_id").IsRequired()
|> ignore .HasDefaultValue (TimeZoneId "America/Denver")
m.Property(fun e -> e.Fonts) it.Property(fun lp -> lp.PageSize).HasColumnName("page_size").IsRequired().HasDefaultValue 100
.HasColumnName("ListFonts") it.Property(fun lp -> lp.AsOfDateDisplay).HasColumnName("as_of_date_display").IsRequired()
.IsRequired() .HasMaxLength(1).HasDefaultValue NoDisplay
.HasDefaultValue "Century Gothic,Tahoma,Luxi Sans,sans-serif" } |> List.ofSeq |> ignore)
|> ignore
m.Property(fun e -> e.HeadingColor)
.HasColumnName("HeadingColor")
.IsRequired()
.HasDefaultValue "maroon"
|> ignore
m.Property(fun e -> e.LineColor)
.HasColumnName("LineColor")
.IsRequired()
.HasDefaultValue "navy"
|> ignore
m.Property(fun e -> e.HeadingFontSize)
.HasColumnName("HeadingFontSize")
.IsRequired()
.HasDefaultValue 16
|> ignore
m.Property(fun e -> e.TextFontSize)
.HasColumnName("TextFontSize")
.IsRequired()
.HasDefaultValue 12
|> ignore
m.Property(fun e -> e.RequestSort)
.HasColumnName("RequestSort")
.IsRequired()
.HasMaxLength(1)
.HasDefaultValue SortByDate
|> ignore
m.Property(fun e -> e.GroupPassword)
.HasColumnName("GroupPassword")
.IsRequired()
.HasDefaultValue ""
|> ignore
m.Property(fun e -> e.DefaultEmailType)
.HasColumnName("DefaultEmailType")
.IsRequired()
.HasDefaultValue HtmlFormat
|> ignore
m.Property(fun e -> e.IsPublic)
.HasColumnName("IsPublic")
.IsRequired()
.HasDefaultValue false
|> ignore
m.Property(fun e -> e.TimeZoneId)
.HasColumnName("TimeZoneId")
.IsRequired()
.HasDefaultValue "America/Denver"
|> ignore
m.Property(fun e -> e.PageSize)
.HasColumnName("PageSize")
.IsRequired()
.HasDefaultValue 100
|> ignore
m.Property(fun e -> e.AsOfDateDisplay)
.HasColumnName("AsOfDateDisplay")
.IsRequired()
.HasMaxLength(1)
.HasDefaultValue NoDisplay
|> ignore)
|> ignore |> ignore
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty("SmallGroupId") mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.SmallGroupId)
.SetValueConverter(Converters.SmallGroupIdConverter ()) .SetValueConverter(Converters.SmallGroupIdConverter ())
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty("RequestSort") mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.RequestSort)
.SetValueConverter(Converters.RequestSortConverter ()) .SetValueConverter(Converters.RequestSortConverter ())
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty("DefaultEmailType") mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.DefaultEmailType)
.SetValueConverter(Converters.EmailFormatConverter ()) .SetValueConverter(Converters.EmailFormatConverter ())
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty("TimeZoneId") mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.TimeZoneId)
.SetValueConverter(Converters.TimeZoneIdConverter ()) .SetValueConverter(Converters.TimeZoneIdConverter ())
mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty("AsOfDateDisplay") mb.Model.FindEntityType(typeof<ListPreferences>).FindProperty(nameof ListPreferences.empty.AsOfDateDisplay)
.SetValueConverter(Converters.AsOfDateDisplayConverter ()) .SetValueConverter(Converters.AsOfDateDisplayConverter ())
@ -655,19 +600,22 @@ with
} }
/// Configure EF for this entity /// Configure EF for this entity
static member internal configureEF (mb : ModelBuilder) = static member internal ConfigureEF (mb : ModelBuilder) =
mb.Entity<Member> (fun m -> mb.Entity<Member> (fun it ->
m.ToTable "Member" |> ignore seq<obj> {
m.Property(fun e -> e.Id).HasColumnName "MemberId" |> ignore it.ToTable "member"
m.Property(fun e -> e.SmallGroupId).HasColumnName "SmallGroupId" |> ignore it.Property(fun m -> m.Id).HasColumnName "id"
m.Property(fun e -> e.Name).HasColumnName("MemberName").IsRequired() |> ignore it.Property(fun m -> m.SmallGroupId).HasColumnName("small_group_id").IsRequired ()
m.Property(fun e -> e.Email).HasColumnName("Email").IsRequired() |> ignore it.Property(fun m -> m.Name).HasColumnName("member_name").IsRequired ()
m.Property(fun e -> e.Format).HasColumnName "Format" |> ignore) it.Property(fun m -> m.Email).HasColumnName("email").IsRequired ()
it.Property(fun m -> m.Format).HasColumnName "email_format"
} |> List.ofSeq |> ignore)
|> ignore |> ignore
mb.Model.FindEntityType(typeof<Member>).FindProperty("Id").SetValueConverter(Converters.MemberIdConverter ()) mb.Model.FindEntityType(typeof<Member>).FindProperty(nameof Member.empty.Id)
mb.Model.FindEntityType(typeof<Member>).FindProperty("SmallGroupId") .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("Format") mb.Model.FindEntityType(typeof<Member>).FindProperty(nameof Member.empty.Format)
.SetValueConverter(Converters.EmailFormatOptionConverter ()) .SetValueConverter(Converters.EmailFormatOptionConverter ())
@ -713,63 +661,62 @@ with
/// An empty request /// An empty request
static member empty = static member empty =
{ Id = PrayerRequestId Guid.Empty { Id = PrayerRequestId Guid.Empty
RequestType = CurrentRequest RequestType = CurrentRequest
UserId = UserId Guid.Empty UserId = UserId Guid.Empty
SmallGroupId = SmallGroupId Guid.Empty SmallGroupId = SmallGroupId Guid.Empty
EnteredDate = DateTime.MinValue EnteredDate = DateTime.MinValue
UpdatedDate = DateTime.MinValue UpdatedDate = DateTime.MinValue
Requestor = None Requestor = None
Text = "" Text = ""
NotifyChaplain = false NotifyChaplain = false
User = User.empty User = User.empty
SmallGroup = SmallGroup.empty SmallGroup = SmallGroup.empty
Expiration = Automatic Expiration = Automatic
} }
/// Is this request expired? /// Is this request expired?
member this.isExpired (curr : DateTime) expDays = member this.IsExpired (curr : DateTime) expDays =
match this.Expiration with match this.Expiration, this.RequestType with
| Forced -> true | Forced, _ -> true
| Manual -> false | Manual, _
| Automatic -> | Automatic, LongTermRequest
match this.RequestType with | Automatic, Expecting -> false
| LongTermRequest | Automatic, _ -> curr.AddDays(-(float expDays)).Date > this.UpdatedDate.Date // Automatic expiration
| Expecting -> false
| _ -> curr.AddDays(-(float expDays)).Date > this.UpdatedDate.Date // Automatic expiration
/// Is an update required for this long-term request? /// Is an update required for this long-term request?
member this.updateRequired curr expDays updWeeks = member this.UpdateRequired curr expDays updWeeks =
match this.isExpired curr expDays with if this.IsExpired curr expDays then false
| true -> false else curr.AddDays(-(float (updWeeks * 7))).Date > this.UpdatedDate.Date
| false -> curr.AddDays(-(float (updWeeks * 7))).Date > this.UpdatedDate.Date
/// Configure EF for this entity /// Configure EF for this entity
static member internal configureEF (mb : ModelBuilder) = static member internal ConfigureEF (mb : ModelBuilder) =
mb.Entity<PrayerRequest> (fun m -> mb.Entity<PrayerRequest> (fun it ->
m.ToTable "PrayerRequest" |> ignore seq<obj> {
m.Property(fun e -> e.Id).HasColumnName "PrayerRequestId" |> ignore it.ToTable "prayer_request"
m.Property(fun e -> e.RequestType).HasColumnName("RequestType").IsRequired() |> ignore it.Property(fun pr -> pr.Id).HasColumnName "id"
m.Property(fun e -> e.UserId).HasColumnName "UserId" |> ignore it.Property(fun pr -> pr.RequestType).HasColumnName("request_type").IsRequired ()
m.Property(fun e -> e.SmallGroupId).HasColumnName "SmallGroupId" |> ignore it.Property(fun pr -> pr.UserId).HasColumnName "user_id"
m.Property(fun e -> e.EnteredDate).HasColumnName "EnteredDate" |> ignore it.Property(fun pr -> pr.SmallGroupId).HasColumnName "small_group_id"
m.Property(fun e -> e.UpdatedDate).HasColumnName "UpdatedDate" |> ignore it.Property(fun pr -> pr.EnteredDate).HasColumnName "entered_date"
m.Property(fun e -> e.Requestor).HasColumnName "Requestor" |> ignore it.Property(fun pr -> pr.UpdatedDate).HasColumnName "updated_date"
m.Property(fun e -> e.Text).HasColumnName("Text").IsRequired() |> ignore it.Property(fun pr -> pr.Requestor).HasColumnName "requestor"
m.Property(fun e -> e.NotifyChaplain).HasColumnName "NotifyChaplain" |> ignore it.Property(fun pr -> pr.Text).HasColumnName("request_text").IsRequired ()
m.Property(fun e -> e.Expiration).HasColumnName "Expiration" |> ignore) it.Property(fun pr -> pr.NotifyChaplain).HasColumnName "notify_chaplain"
it.Property(fun pr -> pr.Expiration).HasColumnName "expiration"
} |> List.ofSeq |> ignore)
|> ignore |> ignore
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty("Id") mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.Id)
.SetValueConverter(Converters.PrayerRequestIdConverter ()) .SetValueConverter(Converters.PrayerRequestIdConverter ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty("RequestType") mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.RequestType)
.SetValueConverter(Converters.PrayerRequestTypeConverter ()) .SetValueConverter(Converters.PrayerRequestTypeConverter ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty("UserId") mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.UserId)
.SetValueConverter(Converters.UserIdConverter ()) .SetValueConverter(Converters.UserIdConverter ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty("SmallGroupId") mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.SmallGroupId)
.SetValueConverter(Converters.SmallGroupIdConverter ()) .SetValueConverter(Converters.SmallGroupIdConverter ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty("Requestor") mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.Requestor)
.SetValueConverter(OptionConverter<string> ()) .SetValueConverter(OptionConverter<string> ())
mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty("Expiration") mb.Model.FindEntityType(typeof<PrayerRequest>).FindProperty(nameof PrayerRequest.empty.Expiration)
.SetValueConverter(Converters.ExpirationConverter ()) .SetValueConverter(Converters.ExpirationConverter ())
@ -814,8 +761,8 @@ with
} }
/// Get the local date for this group /// Get the local date for this group
member this.localTimeNow (clock : IClock) = member this.LocalTimeNow (clock : IClock) =
match clock with null -> nullArg "clock" | _ -> () if isNull clock then nullArg (nameof clock)
let tzId = TimeZoneId.toString this.Preferences.TimeZoneId let tzId = TimeZoneId.toString this.Preferences.TimeZoneId
let tz = let tz =
if DateTimeZoneProviders.Tzdb.Ids.Contains tzId then DateTimeZoneProviders.Tzdb[tzId] if DateTimeZoneProviders.Tzdb.Ids.Contains tzId then DateTimeZoneProviders.Tzdb[tzId]
@ -823,21 +770,26 @@ with
clock.GetCurrentInstant().InZone(tz).ToDateTimeUnspecified () clock.GetCurrentInstant().InZone(tz).ToDateTimeUnspecified ()
/// Get the local date for this group /// Get the local date for this group
member this.localDateNow clock = member this.LocalDateNow clock =
(this.localTimeNow clock).Date (this.LocalTimeNow clock).Date
/// Configure EF for this entity /// Configure EF for this entity
static member internal configureEF (mb : ModelBuilder) = static member internal ConfigureEF (mb : ModelBuilder) =
mb.Entity<SmallGroup> (fun m -> mb.Entity<SmallGroup> (fun it ->
m.ToTable "SmallGroup" |> ignore seq<obj> {
m.Property(fun e -> e.Id).HasColumnName "SmallGroupId" |> ignore it.ToTable "small_group"
m.Property(fun e -> e.ChurchId).HasColumnName "ChurchId" |> ignore it.Property(fun sg -> sg.Id).HasColumnName "id"
m.Property(fun e -> e.Name).HasColumnName("Name").IsRequired() |> ignore it.Property(fun sg -> sg.ChurchId).HasColumnName "church_id"
m.HasOne(fun e -> e.Preferences) |> ignore) it.Property(fun sg -> sg.Name).HasColumnName("group_name").IsRequired ()
it.HasOne(fun sg -> sg.Preferences)
.WithOne()
.HasPrincipalKey(fun sg -> sg.Id :> obj)
.HasForeignKey(fun (lp : ListPreferences) -> lp.SmallGroupId :> obj)
} |> List.ofSeq |> ignore)
|> ignore |> ignore
mb.Model.FindEntityType(typeof<SmallGroup>).FindProperty("Id") mb.Model.FindEntityType(typeof<SmallGroup>).FindProperty(nameof SmallGroup.empty.Id)
.SetValueConverter(Converters.SmallGroupIdConverter ()) .SetValueConverter(Converters.SmallGroupIdConverter ())
mb.Model.FindEntityType(typeof<SmallGroup>).FindProperty("ChurchId") mb.Model.FindEntityType(typeof<SmallGroup>).FindProperty(nameof SmallGroup.empty.ChurchId)
.SetValueConverter(Converters.ChurchIdConverter ()) .SetValueConverter(Converters.ChurchIdConverter ())
@ -866,15 +818,17 @@ with
} }
/// Configure EF for this entity /// Configure EF for this entity
static member internal configureEF (mb : ModelBuilder) = static member internal ConfigureEF (mb : ModelBuilder) =
mb.Entity<TimeZone> ( fun m -> mb.Entity<TimeZone> (fun it ->
m.ToTable "TimeZone" |> ignore seq<obj> {
m.Property(fun e -> e.Id).HasColumnName "TimeZoneId" |> ignore it.ToTable "time_zone"
m.Property(fun e -> e.Description).HasColumnName("Description").IsRequired() |> ignore it.Property(fun tz -> tz.Id).HasColumnName "id"
m.Property(fun e -> e.SortOrder).HasColumnName "SortOrder" |> ignore it.Property(fun tz -> tz.Description).HasColumnName("description").IsRequired ()
m.Property(fun e -> e.IsActive).HasColumnName "IsActive" |> ignore) it.Property(fun tz -> tz.SortOrder).HasColumnName "sort_order"
it.Property(fun tz -> tz.IsActive).HasColumnName "is_active"
} |> List.ofSeq |> ignore)
|> ignore |> ignore
mb.Model.FindEntityType(typeof<TimeZone>).FindProperty("Id") mb.Model.FindEntityType(typeof<TimeZone>).FindProperty(nameof TimeZone.empty.Id)
.SetValueConverter(Converters.TimeZoneIdConverter ()) .SetValueConverter(Converters.TimeZoneIdConverter ())
@ -919,24 +873,27 @@ with
} }
/// The full name of the user /// The full name of the user
member this.fullName = member this.Name =
$"{this.FirstName} {this.LastName}" $"{this.FirstName} {this.LastName}"
/// Configure EF for this entity /// Configure EF for this entity
static member internal configureEF (mb : ModelBuilder) = static member internal ConfigureEF (mb : ModelBuilder) =
mb.Entity<User> (fun m -> mb.Entity<User> (fun it ->
m.ToTable "User" |> ignore seq<obj> {
m.Ignore(fun e -> e.fullName :> obj) |> ignore it.ToTable "pt_user"
m.Property(fun e -> e.Id).HasColumnName "UserId" |> ignore it.Ignore(fun u -> u.Name :> obj)
m.Property(fun e -> e.FirstName).HasColumnName("FirstName").IsRequired() |> ignore it.Property(fun u -> u.Id).HasColumnName "id"
m.Property(fun e -> e.LastName).HasColumnName("LastName").IsRequired() |> ignore it.Property(fun u -> u.FirstName).HasColumnName("first_name").IsRequired ()
m.Property(fun e -> e.Email).HasColumnName("EmailAddress").IsRequired() |> ignore it.Property(fun u -> u.LastName).HasColumnName("last_name").IsRequired ()
m.Property(fun e -> e.IsAdmin).HasColumnName "IsSystemAdmin" |> ignore it.Property(fun u -> u.Email).HasColumnName("email").IsRequired ()
m.Property(fun e -> e.PasswordHash).HasColumnName("PasswordHash").IsRequired() |> ignore it.Property(fun u -> u.IsAdmin).HasColumnName "is_admin"
m.Property(fun e -> e.Salt).HasColumnName "Salt" |> ignore) it.Property(fun u -> u.PasswordHash).HasColumnName("password_hash").IsRequired ()
it.Property(fun u -> u.Salt).HasColumnName "salt"
} |> List.ofSeq |> ignore)
|> ignore |> ignore
mb.Model.FindEntityType(typeof<User>).FindProperty("Id").SetValueConverter(Converters.UserIdConverter ()) mb.Model.FindEntityType(typeof<User>).FindProperty(nameof User.empty.Id)
mb.Model.FindEntityType(typeof<User>).FindProperty("Salt") .SetValueConverter(Converters.UserIdConverter ())
mb.Model.FindEntityType(typeof<User>).FindProperty(nameof User.empty.Salt)
.SetValueConverter(OptionConverter<Guid> ()) .SetValueConverter(OptionConverter<Guid> ())
@ -965,23 +922,23 @@ with
} }
/// Configure EF for this entity /// Configure EF for this entity
static member internal configureEF (mb : ModelBuilder) = static member internal ConfigureEF (mb : ModelBuilder) =
mb.Entity<UserSmallGroup> (fun m -> mb.Entity<UserSmallGroup> (fun it ->
m.ToTable "User_SmallGroup" |> ignore seq<obj> {
m.HasKey(fun e -> {| UserId = e.UserId; SmallGroupId = e.SmallGroupId |} :> obj) |> ignore it.ToTable "user_small_group"
m.Property(fun e -> e.UserId).HasColumnName "UserId" |> ignore it.HasKey (nameof UserSmallGroup.empty.UserId, nameof UserSmallGroup.empty.SmallGroupId)
m.Property(fun e -> e.SmallGroupId).HasColumnName "SmallGroupId" |> ignore it.Property(fun usg -> usg.UserId).HasColumnName "user_id"
m.HasOne(fun e -> e.User) it.Property(fun usg -> usg.SmallGroupId).HasColumnName "small_group_id"
.WithMany(fun e -> e.SmallGroups :> IEnumerable<UserSmallGroup>) it.HasOne(fun usg -> usg.User)
.HasForeignKey(fun e -> e.UserId :> obj) .WithMany(fun u -> u.SmallGroups :> IEnumerable<UserSmallGroup>)
|> ignore .HasForeignKey(fun usg -> usg.UserId :> obj)
m.HasOne(fun e -> e.SmallGroup) it.HasOne(fun usg -> usg.SmallGroup)
.WithMany(fun e -> e.Users :> IEnumerable<UserSmallGroup>) .WithMany(fun sg -> sg.Users :> IEnumerable<UserSmallGroup>)
.HasForeignKey(fun e -> e.SmallGroupId :> obj) .HasForeignKey(fun usg -> usg.SmallGroupId :> obj)
|> ignore) } |> List.ofSeq |> ignore)
|> ignore |> ignore
mb.Model.FindEntityType(typeof<UserSmallGroup>).FindProperty("UserId") mb.Model.FindEntityType(typeof<UserSmallGroup>).FindProperty(nameof UserSmallGroup.empty.UserId)
.SetValueConverter(Converters.UserIdConverter ()) .SetValueConverter(Converters.UserIdConverter ())
mb.Model.FindEntityType(typeof<UserSmallGroup>).FindProperty("SmallGroupId") mb.Model.FindEntityType(typeof<UserSmallGroup>).FindProperty(nameof UserSmallGroup.empty.SmallGroupId)
.SetValueConverter(Converters.SmallGroupIdConverter ()) .SetValueConverter(Converters.SmallGroupIdConverter ())

View File

@ -1,514 +1,389 @@
namespace PrayerTracker.Migrations namespace PrayerTracker.Migrations
open System
open Microsoft.EntityFrameworkCore open Microsoft.EntityFrameworkCore
open Microsoft.EntityFrameworkCore.Infrastructure open Microsoft.EntityFrameworkCore.Infrastructure
open Microsoft.EntityFrameworkCore.Migrations open Microsoft.EntityFrameworkCore.Migrations
open Microsoft.EntityFrameworkCore.Migrations.Operations
open Microsoft.EntityFrameworkCore.Migrations.Operations.Builders
open Npgsql.EntityFrameworkCore.PostgreSQL.Metadata open Npgsql.EntityFrameworkCore.PostgreSQL.Metadata
open PrayerTracker open PrayerTracker
open PrayerTracker.Entities open PrayerTracker.Entities
open System
// fsharplint:disable RecordFieldNames
type ChurchTable =
{ churchId : OperationBuilder<AddColumnOperation>
city : OperationBuilder<AddColumnOperation>
hasInterface : OperationBuilder<AddColumnOperation>
interfaceAddress : OperationBuilder<AddColumnOperation>
name : OperationBuilder<AddColumnOperation>
st : OperationBuilder<AddColumnOperation>
}
type ListPreferencesTable =
{ smallGroupId : OperationBuilder<AddColumnOperation>
daysToExpire : OperationBuilder<AddColumnOperation>
daysToKeepNew : OperationBuilder<AddColumnOperation>
defaultEmailType : OperationBuilder<AddColumnOperation>
emailFromAddress : OperationBuilder<AddColumnOperation>
emailFromName : OperationBuilder<AddColumnOperation>
groupPassword : OperationBuilder<AddColumnOperation>
headingColor : OperationBuilder<AddColumnOperation>
headingFontSize : OperationBuilder<AddColumnOperation>
isPublic : OperationBuilder<AddColumnOperation>
lineColor : OperationBuilder<AddColumnOperation>
listFonts : OperationBuilder<AddColumnOperation>
longTermUpdateWeeks : OperationBuilder<AddColumnOperation>
requestSort : OperationBuilder<AddColumnOperation>
textFontSize : OperationBuilder<AddColumnOperation>
timeZoneId : OperationBuilder<AddColumnOperation>
pageSize : OperationBuilder<AddColumnOperation>
asOfDateDisplay : OperationBuilder<AddColumnOperation>
}
type MemberTable =
{ memberId : OperationBuilder<AddColumnOperation>
email : OperationBuilder<AddColumnOperation>
format : OperationBuilder<AddColumnOperation>
memberName : OperationBuilder<AddColumnOperation>
smallGroupId : OperationBuilder<AddColumnOperation>
}
type PrayerRequestTable =
{ prayerRequestId : OperationBuilder<AddColumnOperation>
enteredDate : OperationBuilder<AddColumnOperation>
expiration : OperationBuilder<AddColumnOperation>
notifyChaplain : OperationBuilder<AddColumnOperation>
requestType : OperationBuilder<AddColumnOperation>
requestor : OperationBuilder<AddColumnOperation>
smallGroupId : OperationBuilder<AddColumnOperation>
text : OperationBuilder<AddColumnOperation>
updatedDate : OperationBuilder<AddColumnOperation>
userId : OperationBuilder<AddColumnOperation>
}
type SmallGroupTable =
{ smallGroupId : OperationBuilder<AddColumnOperation>
churchId : OperationBuilder<AddColumnOperation>
name : OperationBuilder<AddColumnOperation>
}
type TimeZoneTable =
{ timeZoneId : OperationBuilder<AddColumnOperation>
description : OperationBuilder<AddColumnOperation>
isActive : OperationBuilder<AddColumnOperation>
sortOrder : OperationBuilder<AddColumnOperation>
}
type UserSmallGroupTable =
{ userId : OperationBuilder<AddColumnOperation>
smallGroupId : OperationBuilder<AddColumnOperation>
}
type UserTable =
{ userId : OperationBuilder<AddColumnOperation>
emailAddress : OperationBuilder<AddColumnOperation>
firstName : OperationBuilder<AddColumnOperation>
isAdmin : OperationBuilder<AddColumnOperation>
lastName : OperationBuilder<AddColumnOperation>
passwordHash : OperationBuilder<AddColumnOperation>
salt : OperationBuilder<AddColumnOperation>
}
[<DbContext (typeof<AppDbContext>)>] [<DbContext (typeof<AppDbContext>)>]
[<Migration "20161217153124_InitialDatabase">] [<Migration "20161217153124_InitialDatabase">]
type InitialDatabase () = type InitialDatabase () =
inherit Migration () inherit Migration ()
override __.Up (migrationBuilder : MigrationBuilder) = override _.Up (migrationBuilder : MigrationBuilder) =
migrationBuilder.EnsureSchema (name = "pt") migrationBuilder.EnsureSchema (name = "pt")
|> ignore |> ignore
migrationBuilder.CreateTable ( migrationBuilder.CreateTable (
name = "Church", name = "church",
schema = "pt", schema = "pt",
columns = columns = (fun table ->
(fun table -> {| Id = table.Column<Guid> (name = "id", nullable = false)
{ churchId = table.Column<Guid> (name = "ChurchId", nullable = false) City = table.Column<string> (name = "city", nullable = false)
city = table.Column<string> (name = "City", nullable = false) HasVpsInterface = table.Column<bool> (name = "has_vps_interface", nullable = false)
hasInterface = table.Column<bool> (name = "HasVirtualPrayerRoomInterface", nullable = false) InterfaceAddress = table.Column<string> (name = "interface_address", nullable = true)
interfaceAddress = table.Column<string> (name = "InterfaceAddress", nullable = true) Name = table.Column<string> (name = "church_Name", nullable = false)
name = table.Column<string> (name = "Name", nullable = false) State = table.Column<string> (name = "state", nullable = false, maxLength = Nullable<int> 2)
st = table.Column<string> (name = "ST", nullable = false, maxLength = Nullable<int> 2) |}),
}), constraints = fun table ->
constraints = table.PrimaryKey ("pk_church", fun x -> upcast x.Id) |> ignore)
fun table -> |> ignore
table.PrimaryKey ("PK_Church", fun x -> upcast x.churchId) |> ignore)
|> ignore
migrationBuilder.CreateTable ( migrationBuilder.CreateTable (
name = "TimeZone", name = "time_zone",
schema = "pt", schema = "pt",
columns = columns = (fun table ->
(fun table -> {| Id = table.Column<string> (name = "id", nullable = false)
{ timeZoneId = table.Column<string> (name = "TimeZoneId", nullable = false) Description = table.Column<string> (name = "description", nullable = false)
description = table.Column<string> (name = "Description", nullable = false) IsActive = table.Column<bool> (name = "is_active", nullable = false)
isActive = table.Column<bool> (name = "IsActive", nullable = false) SortOrder = table.Column<int> (name = "sort_order", nullable = false)
sortOrder = table.Column<int> (name = "SortOrder", nullable = false) |}),
}), constraints = fun table ->
constraints = table.PrimaryKey ("pk_time_zone", fun x -> upcast x.Id) |> ignore)
fun table -> |> ignore
table.PrimaryKey ("PK_TimeZone", fun x -> upcast x.timeZoneId) |> ignore)
|> ignore
migrationBuilder.CreateTable ( migrationBuilder.CreateTable (
name = "User", name = "pt_user",
schema = "pt", schema = "pt",
columns = columns = (fun table ->
(fun table -> {| Id = table.Column<Guid> (name = "id", nullable = false)
{ userId = table.Column<Guid> (name = "UserId", nullable = false) Email = table.Column<string> (name = "email", nullable = false)
emailAddress = table.Column<string> (name = "EmailAddress", nullable = false) FirstName = table.Column<string> (name = "first_name", nullable = false)
firstName = table.Column<string> (name = "FirstName", nullable = false) IsAdmin = table.Column<bool> (name = "is_admin", nullable = false)
isAdmin = table.Column<bool> (name = "IsSystemAdmin", nullable = false) LastName = table.Column<string> (name = "last_name", nullable = false)
lastName = table.Column<string> (name = "LastName", nullable = false) PasswordHash = table.Column<string> (name = "password_hash", nullable = false)
passwordHash = table.Column<string> (name = "PasswordHash", nullable = false) Salt = table.Column<Guid> (name = "salt", nullable = true)
salt = table.Column<Guid> (name = "Salt", nullable = true) |}),
}), constraints = fun table ->
constraints = table.PrimaryKey("pk_pt_user", fun x -> upcast x.Id) |> ignore)
fun table -> |> ignore
table.PrimaryKey("PK_User", fun x -> upcast x.userId) |> ignore)
|> ignore
migrationBuilder.CreateTable ( migrationBuilder.CreateTable (
name = "SmallGroup", name = "small_group",
schema = "pt", schema = "pt",
columns = columns = (fun table ->
(fun table -> {| Id = table.Column<Guid> (name = "id", nullable = false)
{ smallGroupId = table.Column<Guid> (name = "SmallGroupId", nullable = false) ChurchId = table.Column<Guid> (name = "church_id", nullable = false)
churchId = table.Column<Guid> (name = "ChurchId", nullable = false) Name = table.Column<string> (name = "group_name", nullable = false)
name = table.Column<string> (name = "Name", nullable = false) |}),
}), constraints = fun table ->
constraints = table.PrimaryKey ("pk_small_group", fun x -> upcast x.Id) |> ignore
fun table -> table.ForeignKey (
table.PrimaryKey ("PK_SmallGroup", fun x -> upcast x.smallGroupId) |> ignore name = "fk_small_group_church_id",
table.ForeignKey ( column = (fun x -> upcast x.ChurchId),
name = "FK_SmallGroup_Church_ChurchId", principalSchema = "pt",
column = (fun x -> upcast x.churchId), principalTable = "church",
principalSchema = "pt", principalColumn = "id",
principalTable = "Church", onDelete = ReferentialAction.Cascade)
principalColumn = "ChurchId", |> ignore)
onDelete = ReferentialAction.Cascade) |> ignore
|> ignore)
|> ignore
migrationBuilder.CreateTable ( migrationBuilder.CreateTable (
name = "ListPreference", name = "list_preference",
schema = "pt", schema = "pt",
columns = columns = (fun table ->
(fun table -> {| SmallGroupId = table.Column<Guid> (name = "small_group_id", nullable = false)
{ smallGroupId = table.Column<Guid> (name = "SmallGroupId", nullable = false) AsOfDateDisplay = table.Column<string> (name = "as_of_date_display", nullable = false, defaultValue = "N", maxLength = Nullable<int> 1)
daysToExpire = table.Column<int> (name = "DaysToExpire", nullable = false, defaultValue = 14) DaysToExpire = table.Column<int> (name = "days_to_expire", nullable = false, defaultValue = 14)
daysToKeepNew = table.Column<int> (name = "DaysToKeepNew", nullable = false, defaultValue = 7) DaysToKeepNew = table.Column<int> (name = "days_to_keep_new", nullable = false, defaultValue = 7)
defaultEmailType = table.Column<string> (name = "DefaultEmailType", nullable = false, defaultValue = "Html") DefaultEmailType = table.Column<string> (name = "default_email_type", nullable = false, defaultValue = "Html")
emailFromAddress = table.Column<string> (name = "EmailFromAddress", nullable = false, defaultValue = "prayer@djs-consulting.com") EmailFromAddress = table.Column<string> (name = "email_from_address", nullable = false, defaultValue = "prayer@djs-consulting.com")
emailFromName = table.Column<string> (name = "EmailFromName", nullable = false, defaultValue = "PrayerTracker") EmailFromName = table.Column<string> (name = "email_from_name", nullable = false, defaultValue = "PrayerTracker")
groupPassword = table.Column<string> (name = "GroupPassword", nullable = false, defaultValue = "") Fonts = table.Column<string> (name = "fonts", nullable = false, defaultValue = "Century Gothic,Tahoma,Luxi Sans,sans-serif")
headingColor = table.Column<string> (name = "HeadingColor", nullable = false, defaultValue = "maroon") GroupPassword = table.Column<string> (name = "group_password", nullable = false, defaultValue = "")
headingFontSize = table.Column<int> (name = "HeadingFontSize", nullable = false, defaultValue = 16) HeadingColor = table.Column<string> (name = "heading_color", nullable = false, defaultValue = "maroon")
isPublic = table.Column<bool> (name = "IsPublic", nullable = false, defaultValue = false) HeadingFontSize = table.Column<int> (name = "heading_font_size", nullable = false, defaultValue = 16)
lineColor = table.Column<string> (name = "LineColor", nullable = false, defaultValue = "navy") IsPublic = table.Column<bool> (name = "is_public", nullable = false, defaultValue = false)
listFonts = table.Column<string> (name = "ListFonts", nullable = false, defaultValue = "Century Gothic,Tahoma,Luxi Sans,sans-serif") LineColor = table.Column<string> (name = "line_color", nullable = false, defaultValue = "navy")
longTermUpdateWeeks = table.Column<int> (name = "LongTermUpdateWeeks", nullable = false, defaultValue = 4) LongTermUpdateWeeks = table.Column<int> (name = "long_term_update_weeks", nullable = false, defaultValue = 4)
requestSort = table.Column<string> (name = "RequestSort", nullable = false, defaultValue = "D", maxLength = Nullable<int> 1) PageSize = table.Column<int> (name = "page_size", nullable = false, defaultValue = 100)
textFontSize = table.Column<int> (name = "TextFontSize", nullable = false, defaultValue = 12) RequestSort = table.Column<string> (name = "request_sort", nullable = false, defaultValue = "D", maxLength = Nullable<int> 1)
timeZoneId = table.Column<string> (name = "TimeZoneId", nullable = false, defaultValue = "America/Denver") TextFontSize = table.Column<int> (name = "text_font_size", nullable = false, defaultValue = 12)
pageSize = table.Column<int> (name = "PageSize", nullable = false, defaultValue = 100) TimeZoneId = table.Column<string> (name = "time_zone_id", nullable = false, defaultValue = "America/Denver")
asOfDateDisplay = table.Column<string> (name = "AsOfDateDisplay", nullable = false, defaultValue = "N", maxLength = Nullable<int> 1) |}),
}), constraints = fun table ->
constraints = table.PrimaryKey ("pk_list_preference", fun x -> upcast x.SmallGroupId) |> ignore
fun table -> table.ForeignKey (
table.PrimaryKey ("PK_ListPreference", fun x -> upcast x.smallGroupId) |> ignore name = "fk_list_preference_small_group_id",
table.ForeignKey ( column = (fun x -> upcast x.SmallGroupId),
name = "FK_ListPreference_SmallGroup_SmallGroupId", principalSchema = "pt",
column = (fun x -> upcast x.smallGroupId), principalTable = "small_group",
principalSchema = "pt", principalColumn = "id",
principalTable = "SmallGroup", onDelete = ReferentialAction.Cascade)
principalColumn = "SmallGroupId", |> ignore
onDelete = ReferentialAction.Cascade) table.ForeignKey (
|> ignore name = "fk_list_preference_time_zone_id",
table.ForeignKey ( column = (fun x -> upcast x.TimeZoneId),
name = "FK_ListPreference_TimeZone_TimeZoneId", principalSchema = "pt",
column = (fun x -> upcast x.timeZoneId), principalTable = "time_zone",
principalSchema = "pt", principalColumn = "id",
principalTable = "TimeZone", onDelete = ReferentialAction.Cascade)
principalColumn = "TimeZoneId", |> ignore)
onDelete = ReferentialAction.Cascade) |> ignore
|> ignore)
|> ignore
migrationBuilder.CreateTable ( migrationBuilder.CreateTable (
name = "Member", name = "member",
schema = "pt", schema = "pt",
columns = columns = (fun table ->
(fun table -> {| Id = table.Column<Guid> (name = "id", nullable = false)
{ memberId = table.Column<Guid> (name = "MemberId", nullable = false) Email = table.Column<string> (name = "email", nullable = false)
email = table.Column<string> (name = "Email", nullable = false) Format = table.Column<string> (name = "email_format", nullable = true)
format = table.Column<string> (name = "Format", nullable = true) Name = table.Column<string> (name = "member_name", nullable = false)
memberName = table.Column<string> (name = "MemberName", nullable = false) SmallGroupId = table.Column<Guid> (name = "small_group_id", nullable = false)
smallGroupId = table.Column<Guid> (name = "SmallGroupId", nullable = false) |}),
}), constraints = fun table ->
constraints = table.PrimaryKey ("pk_member", fun x -> upcast x.Id) |> ignore
fun table -> table.ForeignKey (
table.PrimaryKey ("PK_Member", fun x -> upcast x.memberId) |> ignore name = "fk_member_small_group_id",
table.ForeignKey ( column = (fun x -> upcast x.SmallGroupId),
name = "FK_Member_SmallGroup_SmallGroupId", principalSchema = "pt",
column = (fun x -> upcast x.smallGroupId), principalTable = "small_group",
principalSchema = "pt", principalColumn = "id",
principalTable = "SmallGroup", onDelete = ReferentialAction.Cascade)
principalColumn = "SmallGroupId", |> ignore)
onDelete = ReferentialAction.Cascade) |> ignore
|> ignore)
|> ignore
migrationBuilder.CreateTable ( migrationBuilder.CreateTable (
name = "PrayerRequest", name = "prayer_request",
schema = "pt", schema = "pt",
columns = columns = (fun table ->
(fun table -> {| Id = table.Column<Guid> (name = "id", nullable = false)
{ prayerRequestId = table.Column<Guid> (name = "PrayerRequestId", nullable = false) Expiration = table.Column<bool> (name = "expiration", nullable = false)
expiration = table.Column<bool> (name = "Expiration", nullable = false) EnteredDate = table.Column<DateTime> (name = "entered_date", nullable = false)
enteredDate = table.Column<DateTime> (name = "EnteredDate", nullable = false) NotifyChaplain = table.Column<bool> (name = "notify_chaplain", nullable = false)
notifyChaplain = table.Column<bool> (name = "NotifyChaplain", nullable = false) RequestType = table.Column<string> (name = "request_type", nullable = false)
requestType = table.Column<string> (name = "RequestType", nullable = false) Requestor = table.Column<string> (name = "requestor", nullable = true)
requestor = table.Column<string> (name = "Requestor", nullable = true) SmallGroupId = table.Column<Guid> (name = "small_group_id", nullable = false)
smallGroupId = table.Column<Guid> (name = "SmallGroupId", nullable = false) Text = table.Column<string> (name = "request_text", nullable = false)
text = table.Column<string> (name = "Text", nullable = false) UpdatedDate = table.Column<DateTime> (name = "updated_date", nullable = false)
updatedDate = table.Column<DateTime> (name = "UpdatedDate", nullable = false) UserId = table.Column<Guid> (name = "user_id", nullable = false)
userId = table.Column<Guid> (name = "UserId", nullable = false) |}),
}), constraints = fun table ->
constraints = table.PrimaryKey ("pk_prayer_request", fun x -> upcast x.Id) |> ignore
fun table -> table.ForeignKey (
table.PrimaryKey ("PK_PrayerRequest", fun x -> upcast x.prayerRequestId) |> ignore name = "fk_prayer_request_small_group_id",
table.ForeignKey ( column = (fun x -> upcast x.SmallGroupId),
name = "FK_PrayerRequest_SmallGroup_SmallGroupId", principalSchema = "pt",
column = (fun x -> upcast x.smallGroupId), principalTable = "small_group",
principalSchema = "pt", principalColumn = "i",
principalTable = "SmallGroup", onDelete = ReferentialAction.Cascade)
principalColumn = "SmallGroupId", |> ignore
onDelete = ReferentialAction.Cascade) table.ForeignKey (
|> ignore name = "fk_prayer_request_user_id",
table.ForeignKey ( column = (fun x -> upcast x.UserId),
name = "FK_PrayerRequest_User_UserId", principalSchema = "pt",
column = (fun x -> upcast x.userId), principalTable = "pt_user",
principalSchema = "pt", principalColumn = "id",
principalTable = "User", onDelete = ReferentialAction.Cascade)
principalColumn = "UserId", |> ignore)
onDelete = ReferentialAction.Cascade) |> ignore
|> ignore)
|> ignore
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name = "User_SmallGroup", name = "user_small_group",
schema = "pt", schema = "pt",
columns = columns = (fun table ->
(fun table -> {| UserId = table.Column<Guid> (name = "user_id", nullable = false)
{ userId = table.Column<Guid> (name = "UserId", nullable = false) SmallGroupId = table.Column<Guid> (name = "small_group_id", nullable = false)
smallGroupId = table.Column<Guid> (name = "SmallGroupId", nullable = false) |}),
}), constraints = fun table ->
constraints = table.PrimaryKey ("pk_user_small_group", fun x -> upcast x) |> ignore
fun table -> table.ForeignKey (
table.PrimaryKey ("PK_User_SmallGroup", fun x -> upcast x) |> ignore name = "fk_user_small_group_small_group_id",
table.ForeignKey ( column = (fun x -> upcast x.SmallGroupId),
name = "FK_User_SmallGroup_SmallGroup_SmallGroupId", principalSchema = "pt",
column = (fun x -> upcast x.smallGroupId), principalTable = "small_group",
principalSchema = "pt", principalColumn = "id",
principalTable = "SmallGroup", onDelete = ReferentialAction.Cascade)
principalColumn = "SmallGroupId", |> ignore
onDelete = ReferentialAction.Cascade) table.ForeignKey (
|> ignore name = "fk_user_small_group_user_id",
table.ForeignKey ( column = (fun x -> upcast x.UserId),
name = "FK_User_SmallGroup_User_UserId", principalSchema = "pt",
column = (fun x -> upcast x.userId), principalTable = "pt_user",
principalSchema = "pt", principalColumn = "id",
principalTable = "User", onDelete = ReferentialAction.Cascade)
principalColumn = "UserId", |> ignore)
onDelete = ReferentialAction.Cascade) |> ignore
|> ignore)
|> ignore
migrationBuilder.CreateIndex (name = "IX_ListPreference_TimeZoneId", schema = "pt", table = "ListPreference", column = "TimeZoneId") |> ignore migrationBuilder.CreateIndex (name = "ix_list_preference_time_zone_id", schema = "pt", table = "list_preference", column = "time_zone_id") |> ignore
migrationBuilder.CreateIndex (name = "IX_Member_SmallGroupId", schema = "pt", table = "Member", column = "SmallGroupId") |> ignore migrationBuilder.CreateIndex (name = "ix_member_small_group_id", schema = "pt", table = "member", column = "small_group_id") |> ignore
migrationBuilder.CreateIndex (name = "IX_PrayerRequest_SmallGroupId", schema = "pt", table = "PrayerRequest", column = "SmallGroupId") |> ignore migrationBuilder.CreateIndex (name = "ix_prayer_request_small_group_id", schema = "pt", table = "prayer_request", column = "small_group_id") |> ignore
migrationBuilder.CreateIndex (name = "IX_PrayerRequest_UserId", schema = "pt", table = "PrayerRequest", column = "UserId") |> ignore migrationBuilder.CreateIndex (name = "ix_prayer_request_user_id", schema = "pt", table = "prayer_request", column = "user_id") |> ignore
migrationBuilder.CreateIndex (name = "IX_SmallGroup_ChurchId", schema = "pt", table = "SmallGroup", column = "ChurchId") |> ignore migrationBuilder.CreateIndex (name = "ix_small_group_church_id", schema = "pt", table = "small_group", column = "church_id") |> ignore
migrationBuilder.CreateIndex (name = "IX_User_SmallGroup_SmallGroupId", schema = "pt", table = "User_SmallGroup", column = "SmallGroupId") |> ignore migrationBuilder.CreateIndex (name = "ix_user_small_group_small_group_id", schema = "pt", table = "user_small_group", column = "small_group_id") |> ignore
override __.Down (migrationBuilder : MigrationBuilder) = override _.Down (migrationBuilder : MigrationBuilder) =
migrationBuilder.DropTable (name = "ListPreference", schema = "pt") |> ignore migrationBuilder.DropTable (name = "list_preference", schema = "pt") |> ignore
migrationBuilder.DropTable (name = "Member", schema = "pt") |> ignore migrationBuilder.DropTable (name = "member", schema = "pt") |> ignore
migrationBuilder.DropTable (name = "PrayerRequest", schema = "pt") |> ignore migrationBuilder.DropTable (name = "prayer_request", schema = "pt") |> ignore
migrationBuilder.DropTable (name = "User_SmallGroup", schema = "pt") |> ignore migrationBuilder.DropTable (name = "user_small_group", schema = "pt") |> ignore
migrationBuilder.DropTable (name = "TimeZone", schema = "pt") |> ignore migrationBuilder.DropTable (name = "time_zone", schema = "pt") |> ignore
migrationBuilder.DropTable (name = "SmallGroup", schema = "pt") |> ignore migrationBuilder.DropTable (name = "small_group", schema = "pt") |> ignore
migrationBuilder.DropTable (name = "User", schema = "pt") |> ignore migrationBuilder.DropTable (name = "pt_user", schema = "pt") |> ignore
migrationBuilder.DropTable (name = "Church", schema = "pt") |> ignore migrationBuilder.DropTable (name = "church", schema = "pt") |> ignore
override __.BuildTargetModel (modelBuilder : ModelBuilder) = override _.BuildTargetModel (modelBuilder : ModelBuilder) =
modelBuilder modelBuilder
.HasDefaultSchema("pt") .HasDefaultSchema("pt")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752") .HasAnnotation("ProductVersion", "1.1.0-rtm-22752")
|> ignore |> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<Church>, fun b ->
typeof<Church>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<string>("City").HasColumnName("city").IsRequired() |> ignore
b.Property<Guid>("churchId").ValueGeneratedOnAdd() |> ignore b.Property<bool>("HasVpsInterface").HasColumnName("has_vps_interface") |> ignore
b.Property<string>("city").IsRequired() |> ignore b.Property<string>("InterfaceAddress").HasColumnName("interface_address") |> ignore
b.Property<bool>("hasInterface") |> ignore b.Property<string>("Name").HasColumnName("church_name").IsRequired() |> ignore
b.Property<string>("interfaceAddress") |> ignore b.Property<string>("State").HasColumnName("state").IsRequired().HasMaxLength(2) |> ignore
b.Property<string>("name").IsRequired() |> ignore b.HasKey("Id") |> ignore
b.Property<string>("st").IsRequired().HasMaxLength(2) |> ignore b.ToTable("church") |> ignore)
b.HasKey("churchId") |> ignore |> ignore
b.ToTable("Church") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<ListPreferences>, fun b ->
typeof<ListPreferences>, b.Property<Guid>("SmallGroupId").HasColumnName("small_group_id") |> ignore
fun b -> b.Property<string>("AsOfDateDisplay").HasColumnName("as_of_date_display").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("N").HasMaxLength(1) |> ignore
b.Property<Guid>("smallGroupId") |> ignore b.Property<int>("DaysToExpire").HasColumnName("days_to_expire").ValueGeneratedOnAdd().HasDefaultValue(14) |> ignore
b.Property<int>("daysToExpire").ValueGeneratedOnAdd().HasDefaultValue(14) |> ignore b.Property<int>("DaysToKeepNew").HasColumnName("days_to_keep_new").ValueGeneratedOnAdd().HasDefaultValue(7) |> ignore
b.Property<int>("daysToKeepNew").ValueGeneratedOnAdd().HasDefaultValue(7) |> ignore b.Property<string>("DefaultEmailType").HasColumnName("default_email_type").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("H") |> ignore
b.Property<string>("defaultEmailType").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("H") |> ignore b.Property<string>("EmailFromAddress").HasColumnName("email_from_address").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("prayer@djs-consulting.com") |> ignore
b.Property<string>("emailFromAddress").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("prayer@djs-consulting.com") |> ignore b.Property<string>("EmailFromName").HasColumnName("email_from_name").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("PrayerTracker") |> ignore
b.Property<string>("emailFromName").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("PrayerTracker") |> ignore b.Property<string>("Fonts").HasColumnName("fonts").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("Century Gothic,Tahoma,Luxi Sans,sans-serif") |> ignore
b.Property<string>("groupPassword").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("") |> ignore b.Property<string>("GroupPassword").HasColumnName("group_password").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("") |> ignore
b.Property<string>("headingColor").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("maroon") |> ignore b.Property<string>("HeadingColor").HasColumnName("heading_color").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("maroon") |> ignore
b.Property<int>("headingFontSize").ValueGeneratedOnAdd().HasDefaultValue(16) |> ignore b.Property<int>("HeadingFontSize").HasColumnName("heading_font_size").ValueGeneratedOnAdd().HasDefaultValue(16) |> ignore
b.Property<bool>("isPublic").ValueGeneratedOnAdd().HasDefaultValue(false) |> ignore b.Property<bool>("IsPublic").HasColumnName("is_public").ValueGeneratedOnAdd().HasDefaultValue(false) |> ignore
b.Property<string>("lineColor").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("navy") |> ignore b.Property<string>("LineColor").HasColumnName("line_color").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("navy") |> ignore
b.Property<string>("listFonts").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("Century Gothic,Tahoma,Luxi Sans,sans-serif") |> ignore b.Property<int>("LongTermUpdateWeeks").HasColumnName("long_term_update_weeks").ValueGeneratedOnAdd().HasDefaultValue(4) |> ignore
b.Property<int>("longTermUpdateWeeks").ValueGeneratedOnAdd().HasDefaultValue(4) |> ignore b.Property<int>("PageSize").HasColumnName("page_size").IsRequired().ValueGeneratedOnAdd().HasDefaultValue(100) |> ignore
b.Property<string>("requestSort").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("D").HasMaxLength(1) |> ignore b.Property<string>("RequestSort").HasColumnName("request_sort").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("D").HasMaxLength(1) |> ignore
b.Property<int>("textFontSize").ValueGeneratedOnAdd().HasDefaultValue(12) |> ignore b.Property<int>("TextFontSize").HasColumnName("text_font_size").ValueGeneratedOnAdd().HasDefaultValue(12) |> ignore
b.Property<string>("timeZoneId").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("America/Denver") |> ignore b.Property<string>("TimeZoneId").HasColumnName("time_zone_id").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("America/Denver") |> ignore
b.Property<int>("pageSize").IsRequired().ValueGeneratedOnAdd().HasDefaultValue(100) |> ignore b.HasKey("SmallGroupId") |> ignore
b.Property<string>("asOfDateDisplay").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("N").HasMaxLength(1) |> ignore b.HasIndex("TimeZoneId").HasDatabaseName "ix_list_preference_time_zone_id" |> ignore
b.HasKey("smallGroupId") |> ignore b.ToTable("list_preference") |> ignore)
b.HasIndex("timeZoneId") |> ignore |> ignore
b.ToTable("ListPreference") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<Member>, fun b ->
typeof<Member>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<string>("Email").HasColumnName("email").IsRequired() |> ignore
b.Property<Guid>("memberId").ValueGeneratedOnAdd() |> ignore b.Property<string>("Format").HasColumnName("email_format") |> ignore
b.Property<string>("email").IsRequired() |> ignore b.Property<string>("Name").HasColumnName("member_name").IsRequired() |> ignore
b.Property<string>("format") |> ignore b.Property<Guid>("SmallGroupId").HasColumnName("small_group_id") |> ignore
b.Property<string>("memberName").IsRequired() |> ignore b.HasKey("Id") |> ignore
b.Property<Guid>("smallGroupId") |> ignore b.HasIndex("SmallGroupId").HasDatabaseName "ix_member_small_group_id" |> ignore
b.HasKey("memberId") |> ignore b.ToTable("member") |> ignore)
b.HasIndex("smallGroupId") |> ignore |> ignore
b.ToTable("Member") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<PrayerRequest>, fun b ->
typeof<PrayerRequest>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<DateTime>("EnteredDate").HasColumnName("entered_date").IsRequired() |> ignore
b.Property<Guid>("prayerRequestId").ValueGeneratedOnAdd() |> ignore b.Property<string>("Expiration").HasColumnName("expiration").IsRequired().HasMaxLength 1 |> ignore
b.Property<DateTime>("enteredDate").IsRequired() |> ignore b.Property<bool>("NotifyChaplain").HasColumnName("notify_chaplain") |> ignore
b.Property<string>("expiration").IsRequired().HasMaxLength 1 |> ignore b.Property<string>("RequestType").HasColumnName("request_type").IsRequired().HasMaxLength 1 |> ignore
b.Property<bool>("notifyChaplain") |> ignore b.Property<string>("Requestor").HasColumnName("requestor") |> ignore
b.Property<string>("requestType").IsRequired().HasMaxLength 1 |> ignore b.Property<Guid>("SmallGroupId").HasColumnName("small_group_id") |> ignore
b.Property<string>("requestor") |> ignore b.Property<string>("Text").HasColumnName("request_text").IsRequired() |> ignore
b.Property<Guid>("smallGroupId") |> ignore b.Property<DateTime>("UpdatedDate").HasColumnName("updated_date") |> ignore
b.Property<string>("text").IsRequired() |> ignore b.Property<Guid>("UserId").HasColumnName("user_id") |> ignore
b.Property<DateTime>("updatedDate") |> ignore b.HasKey("Id") |> ignore
b.Property<Guid>("userId") |> ignore b.HasIndex("SmallGroupId").HasDatabaseName "ix_prayer_request_small_group_id" |> ignore
b.HasKey("prayerRequestId") |> ignore b.HasIndex("UserId").HasDatabaseName "ix_prayer_request_user_id" |> ignore
b.HasIndex("smallGroupId") |> ignore b.ToTable("prayer_request") |> ignore)
b.HasIndex("userId") |> ignore |> ignore
b.ToTable("PrayerRequest") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<SmallGroup>, fun b ->
typeof<SmallGroup>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<Guid>("ChurchId").HasColumnName("church_id") |> ignore
b.Property<Guid>("smallGroupId").ValueGeneratedOnAdd() |> ignore b.Property<string>("Name").HasColumnName("group_name").IsRequired() |> ignore
b.Property<Guid>("churchId") |> ignore b.HasKey("Id") |> ignore
b.Property<string>("name").IsRequired() |> ignore b.HasIndex("ChurchId").HasDatabaseName "ix_small_group_church_id" |> ignore
b.HasKey("smallGroupId") |> ignore b.ToTable("small_group") |> ignore)
b.HasIndex("churchId") |> ignore |> ignore
b.ToTable("SmallGroup") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<TimeZone>, fun b ->
typeof<PrayerTracker.Entities.TimeZone>, b.Property<string>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<string>("Description").HasColumnName("description").IsRequired() |> ignore
b.Property<string>("timeZoneId").ValueGeneratedOnAdd() |> ignore b.Property<bool>("IsActive").HasColumnName("is_active") |> ignore
b.Property<string>("description").IsRequired() |> ignore b.Property<int>("SortOrder").HasColumnName("sort_order") |> ignore
b.Property<bool>("isActive") |> ignore b.HasKey("Id") |> ignore
b.Property<int>("sortOrder") |> ignore b.ToTable("time_zone") |> ignore)
b.HasKey("timeZoneId") |> ignore |> ignore
b.ToTable("TimeZone") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<User>, fun b ->
typeof<User>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<string>("Email").HasColumnName("email").IsRequired() |> ignore
b.Property<Guid>("userId").ValueGeneratedOnAdd() |> ignore b.Property<string>("FirstName").HasColumnName("first_name").IsRequired() |> ignore
b.Property<string>("emailAddress").IsRequired() |> ignore b.Property<bool>("IsAdmin").HasColumnName("is_admin") |> ignore
b.Property<string>("firstName").IsRequired() |> ignore b.Property<string>("LastName").HasColumnName("last_name").IsRequired() |> ignore
b.Property<bool>("isAdmin") |> ignore b.Property<string>("PasswordHash").HasColumnName("password_hash").IsRequired() |> ignore
b.Property<string>("lastName").IsRequired() |> ignore b.Property<Guid>("Salt").HasColumnName("salt") |> ignore
b.Property<string>("passwordHash").IsRequired() |> ignore b.HasKey("Id") |> ignore
b.Property<Guid>("salt") |> ignore b.ToTable("pt_user") |> ignore)
b.HasKey("userId") |> ignore |> ignore
b.ToTable("User") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<UserSmallGroup>, fun b ->
typeof<UserSmallGroup>, b.Property<Guid>("UserId").HasColumnName("user_id") |> ignore
fun b -> b.Property<Guid>("SmallGroupId").HasColumnName("small_group_id") |> ignore
b.Property<Guid>("userId") |> ignore b.HasKey("UserId", "SmallGroupId") |> ignore
b.Property<Guid>("smallGroupId") |> ignore b.HasIndex("SmallGroupId").HasDatabaseName "ix_user_small_group_small_group_id" |> ignore
b.HasKey("userId", "smallGroupId") |> ignore b.ToTable("user_small_group") |> ignore)
b.HasIndex("smallGroupId") |> ignore |> ignore
b.ToTable("User_SmallGroup") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<ListPreferences>, fun b ->
typeof<ListPreferences>, b.HasOne("PrayerTracker.Entities.SmallGroup")
fun b -> .WithOne("Preferences")
b.HasOne("PrayerTracker.Entities.SmallGroup") .HasForeignKey("PrayerTracker.Entities.ListPreferences", "SmallGroupId")
.WithOne("preferences") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("PrayerTracker.Entities.ListPreferences", "smallGroupId") |> ignore
.OnDelete(DeleteBehavior.Cascade) b.HasOne("PrayerTracker.Entities.TimeZone", "TimeZone")
|> ignore .WithMany()
b.HasOne("PrayerTracker.Entities.TimeZone", "timeZone") .HasForeignKey("TimeZoneId")
.WithMany() .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("timeZoneId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<Member>, fun b ->
typeof<Member>, b.HasOne("PrayerTracker.Entities.SmallGroup", "SmallGroup")
fun b -> .WithMany("Members")
b.HasOne("PrayerTracker.Entities.SmallGroup", "smallGroup") .HasForeignKey("SmallGroupId")
.WithMany("members") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("smallGroupId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<PrayerRequest>, fun b ->
typeof<PrayerRequest>, b.HasOne("PrayerTracker.Entities.SmallGroup", "SmallGroup")
fun b -> .WithMany("PrayerRequests")
b.HasOne("PrayerTracker.Entities.SmallGroup", "smallGroup") .HasForeignKey("SmallGroupId")
.WithMany("prayerRequests") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("smallGroupId") |> ignore
.OnDelete(DeleteBehavior.Cascade) b.HasOne("PrayerTracker.Entities.User", "User")
|> ignore .WithMany()
b.HasOne("PrayerTracker.Entities.User", "user") .HasForeignKey("UserId")
.WithMany() .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("userId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<SmallGroup>, fun b ->
typeof<SmallGroup>, b.HasOne("PrayerTracker.Entities.Church", "Church")
fun b -> .WithMany("SmallGroups")
b.HasOne("PrayerTracker.Entities.Church", "Church") .HasForeignKey("ChurchId")
.WithMany("SmallGroups") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("ChurchId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<UserSmallGroup>, fun b ->
typeof<UserSmallGroup>, b.HasOne("PrayerTracker.Entities.SmallGroup", "SmallGroup")
fun b -> .WithMany("Users")
b.HasOne("PrayerTracker.Entities.SmallGroup", "smallGroup") .HasForeignKey("SmallGroupId")
.WithMany("users") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("smallGroupId") |> ignore
.OnDelete(DeleteBehavior.Cascade) b.HasOne("PrayerTracker.Entities.User", "User")
|> ignore .WithMany("SmallGroups")
b.HasOne("PrayerTracker.Entities.User", "user") .HasForeignKey("UserId")
.WithMany("smallGroups") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("userId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore

View File

@ -1,200 +1,174 @@
namespace PrayerTracker.Migrations namespace PrayerTracker.Migrations
open System
open Microsoft.EntityFrameworkCore open Microsoft.EntityFrameworkCore
open Microsoft.EntityFrameworkCore.Infrastructure open Microsoft.EntityFrameworkCore.Infrastructure
open Npgsql.EntityFrameworkCore.PostgreSQL.Metadata open Npgsql.EntityFrameworkCore.PostgreSQL.Metadata
open PrayerTracker open PrayerTracker
open PrayerTracker.Entities open PrayerTracker.Entities
open System
[<DbContext (typeof<AppDbContext>)>] [<DbContext (typeof<AppDbContext>)>]
type AppDbContextModelSnapshot () = type AppDbContextModelSnapshot () =
inherit ModelSnapshot () inherit ModelSnapshot ()
override __.BuildModel (modelBuilder : ModelBuilder) = override _.BuildModel (modelBuilder : ModelBuilder) =
modelBuilder modelBuilder
.HasDefaultSchema("pt") .HasDefaultSchema("pt")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752") .HasAnnotation("ProductVersion", "1.1.0-rtm-22752")
|> ignore |> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<Church>, fun b ->
typeof<Church>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<string>("City").HasColumnName("city").IsRequired() |> ignore
b.Property<Guid>("churchId").ValueGeneratedOnAdd() |> ignore b.Property<bool>("HasVpsInterface").HasColumnName("has_vps_interface") |> ignore
b.Property<string>("city").IsRequired() |> ignore b.Property<string>("InterfaceAddress").HasColumnName("interface_address") |> ignore
b.Property<bool>("hasInterface") |> ignore b.Property<string>("Name").HasColumnName("church_name").IsRequired() |> ignore
b.Property<string>("interfaceAddress") |> ignore b.Property<string>("State").HasColumnName("state").IsRequired().HasMaxLength(2) |> ignore
b.Property<string>("name").IsRequired() |> ignore b.HasKey("Id") |> ignore
b.Property<string>("st").IsRequired().HasMaxLength(2) |> ignore b.ToTable("church") |> ignore)
b.HasKey("churchId") |> ignore |> ignore
b.ToTable("Church") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<ListPreferences>, fun b ->
typeof<ListPreferences>, b.Property<Guid>("SmallGroupId").HasColumnName("small_group_id") |> ignore
fun b -> b.Property<string>("AsOfDateDisplay").HasColumnName("as_of_date_display").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("N").HasMaxLength(1) |> ignore
b.Property<Guid>("smallGroupId") |> ignore b.Property<int>("DaysToExpire").HasColumnName("days_to_expire").ValueGeneratedOnAdd().HasDefaultValue(14) |> ignore
b.Property<int>("daysToExpire").ValueGeneratedOnAdd().HasDefaultValue(14) |> ignore b.Property<int>("DaysToKeepNew").HasColumnName("days_to_keep_new").ValueGeneratedOnAdd().HasDefaultValue(7) |> ignore
b.Property<int>("daysToKeepNew").ValueGeneratedOnAdd().HasDefaultValue(7) |> ignore b.Property<string>("DefaultEmailType").HasColumnName("default_email_type").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("H") |> ignore
b.Property<string>("defaultEmailType").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("H").HasMaxLength(1) |> ignore b.Property<string>("EmailFromAddress").HasColumnName("email_from_address").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("prayer@djs-consulting.com") |> ignore
b.Property<string>("emailFromAddress").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("prayer@djs-consulting.com") |> ignore b.Property<string>("EmailFromName").HasColumnName("email_from_name").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("PrayerTracker") |> ignore
b.Property<string>("emailFromName").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("PrayerTracker") |> ignore b.Property<string>("Fonts").HasColumnName("fonts").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("Century Gothic,Tahoma,Luxi Sans,sans-serif") |> ignore
b.Property<string>("groupPassword").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("") |> ignore b.Property<string>("GroupPassword").HasColumnName("group_password").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("") |> ignore
b.Property<string>("headingColor").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("maroon") |> ignore b.Property<string>("HeadingColor").HasColumnName("heading_color").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("maroon") |> ignore
b.Property<int>("headingFontSize").ValueGeneratedOnAdd().HasDefaultValue(16) |> ignore b.Property<int>("HeadingFontSize").HasColumnName("heading_font_size").ValueGeneratedOnAdd().HasDefaultValue(16) |> ignore
b.Property<bool>("isPublic").ValueGeneratedOnAdd().HasDefaultValue(false) |> ignore b.Property<bool>("IsPublic").HasColumnName("is_public").ValueGeneratedOnAdd().HasDefaultValue(false) |> ignore
b.Property<string>("lineColor").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("navy") |> ignore b.Property<string>("LineColor").HasColumnName("line_color").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("navy") |> ignore
b.Property<string>("listFonts").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("Century Gothic,Tahoma,Luxi Sans,sans-serif") |> ignore b.Property<int>("LongTermUpdateWeeks").HasColumnName("long_term_update_weeks").ValueGeneratedOnAdd().HasDefaultValue(4) |> ignore
b.Property<int>("longTermUpdateWeeks").ValueGeneratedOnAdd().HasDefaultValue(4) |> ignore b.Property<int>("PageSize").HasColumnName("page_size").IsRequired().ValueGeneratedOnAdd().HasDefaultValue(100) |> ignore
b.Property<string>("requestSort").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("D").HasMaxLength(1) |> ignore b.Property<string>("RequestSort").HasColumnName("request_sort").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("D").HasMaxLength(1) |> ignore
b.Property<int>("textFontSize").ValueGeneratedOnAdd().HasDefaultValue(12) |> ignore b.Property<int>("TextFontSize").HasColumnName("text_font_size").ValueGeneratedOnAdd().HasDefaultValue(12) |> ignore
b.Property<string>("timeZoneId").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("America/Denver") |> ignore b.Property<string>("TimeZoneId").HasColumnName("time_zone_id").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("America/Denver") |> ignore
b.Property<int>("pageSize").IsRequired().ValueGeneratedOnAdd().HasDefaultValue(100) |> ignore b.HasKey("SmallGroupId") |> ignore
b.Property<string>("asOfDateDisplay").IsRequired().ValueGeneratedOnAdd().HasDefaultValue("N").HasMaxLength(1) |> ignore b.HasIndex("TimeZoneId").HasDatabaseName "ix_list_preference_time_zone_id" |> ignore
b.HasKey("smallGroupId") |> ignore b.ToTable("list_preference") |> ignore)
b.HasIndex("timeZoneId") |> ignore |> ignore
b.ToTable("ListPreference") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<Member>, fun b ->
typeof<Member>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<string>("Email").HasColumnName("email").IsRequired() |> ignore
b.Property<Guid>("memberId").ValueGeneratedOnAdd() |> ignore b.Property<string>("Format").HasColumnName("email_format") |> ignore
b.Property<string>("email").IsRequired() |> ignore b.Property<string>("Name").HasColumnName("member_name").IsRequired() |> ignore
b.Property<string>("format") |> ignore b.Property<Guid>("SmallGroupId").HasColumnName("small_group_id") |> ignore
b.Property<string>("memberName").IsRequired() |> ignore b.HasKey("Id") |> ignore
b.Property<Guid>("smallGroupId") |> ignore b.HasIndex("SmallGroupId").HasDatabaseName "ix_member_small_group_id" |> ignore
b.HasKey("memberId") |> ignore b.ToTable("member") |> ignore)
b.HasIndex("smallGroupId") |> ignore |> ignore
b.ToTable("Member") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<PrayerRequest>, fun b ->
typeof<PrayerRequest>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<DateTime>("EnteredDate").HasColumnName("entered_date").IsRequired() |> ignore
b.Property<Guid>("prayerRequestId").ValueGeneratedOnAdd() |> ignore b.Property<string>("Expiration").HasColumnName("expiration").IsRequired().HasMaxLength 1 |> ignore
b.Property<DateTime>("enteredDate") |> ignore b.Property<bool>("NotifyChaplain").HasColumnName("notify_chaplain") |> ignore
b.Property<string>("expiration").IsRequired().HasMaxLength(1) |> ignore b.Property<string>("RequestType").HasColumnName("request_type").IsRequired().HasMaxLength 1 |> ignore
b.Property<bool>("notifyChaplain") |> ignore b.Property<string>("Requestor").HasColumnName("requestor") |> ignore
b.Property<string>("requestType").IsRequired().HasMaxLength(1) |> ignore b.Property<Guid>("SmallGroupId").HasColumnName("small_group_id") |> ignore
b.Property<string>("requestor") |> ignore b.Property<string>("Text").HasColumnName("request_text").IsRequired() |> ignore
b.Property<Guid>("smallGroupId") |> ignore b.Property<DateTime>("UpdatedDate").HasColumnName("updated_date") |> ignore
b.Property<string>("text").IsRequired() |> ignore b.Property<Guid>("UserId").HasColumnName("user_id") |> ignore
b.Property<DateTime>("updatedDate") |> ignore b.HasKey("Id") |> ignore
b.Property<Guid>("userId") |> ignore b.HasIndex("SmallGroupId").HasDatabaseName "ix_prayer_request_small_group_id" |> ignore
b.HasKey("prayerRequestId") |> ignore b.HasIndex("UserId").HasDatabaseName "ix_prayer_request_user_id" |> ignore
b.HasIndex("smallGroupId") |> ignore b.ToTable("prayer_request") |> ignore)
b.HasIndex("userId") |> ignore |> ignore
b.ToTable("PrayerRequest") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<SmallGroup>, fun b ->
typeof<SmallGroup>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<Guid>("ChurchId").HasColumnName("church_id") |> ignore
b.Property<Guid>("smallGroupId").ValueGeneratedOnAdd() |> ignore b.Property<string>("Name").HasColumnName("group_name").IsRequired() |> ignore
b.Property<Guid>("churchId") |> ignore b.HasKey("Id") |> ignore
b.Property<string>("name").IsRequired() |> ignore b.HasIndex("ChurchId").HasDatabaseName "ix_small_group_church_id" |> ignore
b.HasKey("smallGroupId") |> ignore b.ToTable("small_group") |> ignore)
b.HasIndex("churchId") |> ignore |> ignore
b.ToTable("SmallGroup") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<TimeZone>, fun b ->
typeof<PrayerTracker.Entities.TimeZone>, b.Property<string>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<string>("Description").HasColumnName("description").IsRequired() |> ignore
b.Property<string>("timeZoneId").ValueGeneratedOnAdd() |> ignore b.Property<bool>("IsActive").HasColumnName("is_active") |> ignore
b.Property<string>("description").IsRequired() |> ignore b.Property<int>("SortOrder").HasColumnName("sort_order") |> ignore
b.Property<bool>("isActive") |> ignore b.HasKey("Id") |> ignore
b.Property<int>("sortOrder") |> ignore b.ToTable("time_zone") |> ignore)
b.HasKey("timeZoneId") |> ignore |> ignore
b.ToTable("TimeZone") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<User>, fun b ->
typeof<User>, b.Property<Guid>("Id").HasColumnName("id").ValueGeneratedOnAdd() |> ignore
fun b -> b.Property<string>("Email").HasColumnName("email").IsRequired() |> ignore
b.Property<Guid>("userId").ValueGeneratedOnAdd() |> ignore b.Property<string>("FirstName").HasColumnName("first_name").IsRequired() |> ignore
b.Property<string>("emailAddress").IsRequired() |> ignore b.Property<bool>("IsAdmin").HasColumnName("is_admin") |> ignore
b.Property<string>("firstName").IsRequired() |> ignore b.Property<string>("LastName").HasColumnName("last_name").IsRequired() |> ignore
b.Property<bool>("isAdmin") |> ignore b.Property<string>("PasswordHash").HasColumnName("password_hash").IsRequired() |> ignore
b.Property<string>("lastName").IsRequired() |> ignore b.Property<Guid>("Salt").HasColumnName("salt") |> ignore
b.Property<string>("passwordHash").IsRequired() |> ignore b.HasKey("Id") |> ignore
b.Property<Guid>("salt") |> ignore b.ToTable("pt_user") |> ignore)
b.HasKey("userId") |> ignore |> ignore
b.ToTable("User") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<UserSmallGroup>, fun b ->
typeof<UserSmallGroup>, b.Property<Guid>("UserId").HasColumnName("user_id") |> ignore
fun b -> b.Property<Guid>("SmallGroupId").HasColumnName("small_group_id") |> ignore
b.Property<Guid>("userId") |> ignore b.HasKey("UserId", "SmallGroupId") |> ignore
b.Property<Guid>("smallGroupId") |> ignore b.HasIndex("SmallGroupId").HasDatabaseName "ix_user_small_group_small_group_id" |> ignore
b.HasKey("userId", "smallGroupId") |> ignore b.ToTable("user_small_group") |> ignore)
b.HasIndex("smallGroupId") |> ignore |> ignore
b.ToTable("User_SmallGroup") |> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<ListPreferences>, fun b ->
typeof<ListPreferences>, b.HasOne("PrayerTracker.Entities.SmallGroup")
fun b -> .WithOne("Preferences")
b.HasOne("PrayerTracker.Entities.SmallGroup") .HasForeignKey("PrayerTracker.Entities.ListPreferences", "smallGroupId")
.WithOne("preferences") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("PrayerTracker.Entities.ListPreferences", "smallGroupId") |> ignore
.OnDelete(DeleteBehavior.Cascade) b.HasOne("PrayerTracker.Entities.TimeZone", "TimeZone")
|> ignore .WithMany()
b.HasOne("PrayerTracker.Entities.TimeZone", "timeZone") .HasForeignKey("TimeZoneId")
.WithMany() .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("timeZoneId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<Member>, fun b ->
typeof<Member>, b.HasOne("PrayerTracker.Entities.SmallGroup", "SmallGroup")
fun b -> .WithMany("Members")
b.HasOne("PrayerTracker.Entities.SmallGroup", "smallGroup") .HasForeignKey("SmallGroupId")
.WithMany("members") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("smallGroupId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<PrayerRequest>, fun b ->
typeof<PrayerRequest>, b.HasOne("PrayerTracker.Entities.SmallGroup", "SmallGroup")
fun b -> .WithMany("PrayerRequests")
b.HasOne("PrayerTracker.Entities.SmallGroup", "smallGroup") .HasForeignKey("SmallGroupId")
.WithMany("prayerRequests") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("smallGroupId") |> ignore
.OnDelete(DeleteBehavior.Cascade) b.HasOne("PrayerTracker.Entities.User", "User")
|> ignore .WithMany()
b.HasOne("PrayerTracker.Entities.User", "user") .HasForeignKey("UserId")
.WithMany() .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("userId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<SmallGroup>, fun b ->
typeof<SmallGroup>, b.HasOne("PrayerTracker.Entities.Church", "Church")
fun b -> .WithMany("SmallGroups")
b.HasOne("PrayerTracker.Entities.Church", "Church") .HasForeignKey("ChurchId")
.WithMany("SmallGroups") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("ChurchId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore
modelBuilder.Entity ( modelBuilder.Entity (typeof<UserSmallGroup>, fun b ->
typeof<UserSmallGroup>, b.HasOne("PrayerTracker.Entities.SmallGroup", "SmallGroup")
fun b -> .WithMany("Users")
b.HasOne("PrayerTracker.Entities.SmallGroup", "smallGroup") .HasForeignKey("SmallGroupId")
.WithMany("users") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("smallGroupId") |> ignore
.OnDelete(DeleteBehavior.Cascade) b.HasOne("PrayerTracker.Entities.User", "User")
|> ignore .WithMany("SmallGroups")
b.HasOne("PrayerTracker.Entities.User", "user") .HasForeignKey("UserId")
.WithMany("smallGroups") .OnDelete(DeleteBehavior.Cascade)
.HasForeignKey("userId") |> ignore)
.OnDelete(DeleteBehavior.Cascade) |> ignore
|> ignore)
|> ignore

View File

@ -41,7 +41,7 @@ let churchTests =
Expect.equal mt.Name "" "The name should have been blank" Expect.equal mt.Name "" "The name should have been blank"
Expect.equal mt.City "" "The city should have been blank" Expect.equal mt.City "" "The city should have been blank"
Expect.equal mt.State "" "The state should have been blank" Expect.equal mt.State "" "The state should have been blank"
Expect.isFalse mt.HasInterface "The church should not show that it has an interface" Expect.isFalse mt.HasVpsInterface "The church should not show that it has an interface"
Expect.isNone mt.InterfaceAddress "The interface address should not exist" Expect.isNone mt.InterfaceAddress "The interface address should not exist"
Expect.isNotNull mt.SmallGroups "The small groups navigation property should not be null" Expect.isNotNull mt.SmallGroups "The small groups navigation property should not be null"
Expect.isEmpty mt.SmallGroups "There should be no small groups for an empty church" Expect.isEmpty mt.SmallGroups "There should be no small groups for an empty church"
@ -159,61 +159,61 @@ let prayerRequestTests =
Expect.equal mt.User.Id.Value Guid.Empty "The user should have been an empty one" Expect.equal mt.User.Id.Value Guid.Empty "The user should have been an empty one"
Expect.equal mt.SmallGroup.Id.Value Guid.Empty "The small group should have been an empty one" Expect.equal mt.SmallGroup.Id.Value Guid.Empty "The small group should have been an empty one"
} }
test "isExpired always returns false for expecting requests" { test "IsExpired always returns false for expecting requests" {
let req = { PrayerRequest.empty with RequestType = Expecting } let req = { PrayerRequest.empty with RequestType = Expecting }
Expect.isFalse (req.isExpired DateTime.Now 0) "An expecting request should never be considered expired" Expect.isFalse (req.IsExpired DateTime.Now 0) "An expecting request should never be considered expired"
} }
test "isExpired always returns false for manually-expired requests" { test "IsExpired always returns false for manually-expired requests" {
let req = { PrayerRequest.empty with UpdatedDate = DateTime.Now.AddMonths -1; Expiration = Manual } let req = { PrayerRequest.empty with UpdatedDate = DateTime.Now.AddMonths -1; Expiration = Manual }
Expect.isFalse (req.isExpired DateTime.Now 4) "A never-expired request should never be considered expired" Expect.isFalse (req.IsExpired DateTime.Now 4) "A never-expired request should never be considered expired"
} }
test "isExpired always returns false for long term/recurring requests" { test "IsExpired always returns false for long term/recurring requests" {
let req = { PrayerRequest.empty with RequestType = LongTermRequest } let req = { PrayerRequest.empty with RequestType = LongTermRequest }
Expect.isFalse (req.isExpired DateTime.Now 0) Expect.isFalse (req.IsExpired DateTime.Now 0)
"A recurring/long-term request should never be considered expired" "A recurring/long-term request should never be considered expired"
} }
test "isExpired always returns true for force-expired requests" { test "IsExpired always returns true for force-expired requests" {
let req = { PrayerRequest.empty with UpdatedDate = DateTime.Now; Expiration = Forced } let req = { PrayerRequest.empty with UpdatedDate = DateTime.Now; Expiration = Forced }
Expect.isTrue (req.isExpired DateTime.Now 5) "A force-expired request should always be considered expired" Expect.isTrue (req.IsExpired DateTime.Now 5) "A force-expired request should always be considered expired"
} }
test "isExpired returns false for non-expired requests" { test "IsExpired returns false for non-expired requests" {
let now = DateTime.Now let now = DateTime.Now
let req = { PrayerRequest.empty with UpdatedDate = now.AddDays -5. } let req = { PrayerRequest.empty with UpdatedDate = now.AddDays -5. }
Expect.isFalse (req.isExpired now 7) "A request updated 5 days ago should not be considered expired" Expect.isFalse (req.IsExpired now 7) "A request updated 5 days ago should not be considered expired"
} }
test "isExpired returns true for expired requests" { test "IsExpired returns true for expired requests" {
let now = DateTime.Now let now = DateTime.Now
let req = { PrayerRequest.empty with UpdatedDate = now.AddDays -8. } let req = { PrayerRequest.empty with UpdatedDate = now.AddDays -8. }
Expect.isTrue (req.isExpired now 7) "A request updated 8 days ago should be considered expired" Expect.isTrue (req.IsExpired now 7) "A request updated 8 days ago should be considered expired"
} }
test "isExpired returns true for same-day expired requests" { test "IsExpired returns true for same-day expired requests" {
let now = DateTime.Now let now = DateTime.Now
let req = { PrayerRequest.empty with UpdatedDate = now.Date.AddDays(-7.).AddSeconds -1. } let req = { PrayerRequest.empty with UpdatedDate = now.Date.AddDays(-7.).AddSeconds -1. }
Expect.isTrue (req.isExpired now 7) Expect.isTrue (req.IsExpired now 7)
"A request entered a second before midnight should be considered expired" "A request entered a second before midnight should be considered expired"
} }
test "updateRequired returns false for expired requests" { test "UpdateRequired returns false for expired requests" {
let req = { PrayerRequest.empty with Expiration = Forced } let req = { PrayerRequest.empty with Expiration = Forced }
Expect.isFalse (req.updateRequired DateTime.Now 7 4) "An expired request should not require an update" Expect.isFalse (req.UpdateRequired DateTime.Now 7 4) "An expired request should not require an update"
} }
test "updateRequired returns false when an update is not required for an active request" { test "UpdateRequired returns false when an update is not required for an active request" {
let now = DateTime.Now let now = DateTime.Now
let req = let req =
{ PrayerRequest.empty with { PrayerRequest.empty with
RequestType = LongTermRequest RequestType = LongTermRequest
UpdatedDate = now.AddDays -14. UpdatedDate = now.AddDays -14.
} }
Expect.isFalse (req.updateRequired now 7 4) Expect.isFalse (req.UpdateRequired now 7 4)
"An active request updated 14 days ago should not require an update until 28 days" "An active request updated 14 days ago should not require an update until 28 days"
} }
test "updateRequired returns true when an update is required for an active request" { test "UpdateRequired returns true when an update is required for an active request" {
let now = DateTime.Now let now = DateTime.Now
let req = let req =
{ PrayerRequest.empty with { PrayerRequest.empty with
RequestType = LongTermRequest RequestType = LongTermRequest
UpdatedDate = now.AddDays -34. UpdatedDate = now.AddDays -34.
} }
Expect.isTrue (req.updateRequired now 7 4) Expect.isTrue (req.UpdateRequired now 7 4)
"An active request updated 34 days ago should require an update (past 28 days)" "An active request updated 34 days ago should require an update (past 28 days)"
} }
] ]
@ -305,33 +305,33 @@ let smallGroupTests =
Expect.isEmpty mt.Users "There should be no users for an empty small group" Expect.isEmpty mt.Users "There should be no users for an empty small group"
} }
yield! testFixture withFakeClock [ yield! testFixture withFakeClock [
"localTimeNow adjusts the time ahead of UTC", "LocalTimeNow adjusts the time ahead of UTC",
fun clock -> fun clock ->
let grp = let grp =
{ SmallGroup.empty with { SmallGroup.empty with
Preferences = { ListPreferences.empty with TimeZoneId = TimeZoneId "Europe/Berlin" } Preferences = { ListPreferences.empty with TimeZoneId = TimeZoneId "Europe/Berlin" }
} }
Expect.isGreaterThan (grp.localTimeNow clock) now "UTC to Europe/Berlin should have added hours" Expect.isGreaterThan (grp.LocalTimeNow clock) now "UTC to Europe/Berlin should have added hours"
"localTimeNow adjusts the time behind UTC", "LocalTimeNow adjusts the time behind UTC",
fun clock -> fun clock ->
Expect.isLessThan (SmallGroup.empty.localTimeNow clock) now Expect.isLessThan (SmallGroup.empty.LocalTimeNow clock) now
"UTC to America/Denver should have subtracted hours" "UTC to America/Denver should have subtracted hours"
"localTimeNow returns UTC when the time zone is invalid", "LocalTimeNow returns UTC when the time zone is invalid",
fun clock -> fun clock ->
let grp = let grp =
{ SmallGroup.empty with { SmallGroup.empty with
Preferences = { ListPreferences.empty with TimeZoneId = TimeZoneId "garbage" } Preferences = { ListPreferences.empty with TimeZoneId = TimeZoneId "garbage" }
} }
Expect.equal (grp.localTimeNow clock) now "UTC should have been returned for an invalid time zone" Expect.equal (grp.LocalTimeNow clock) now "UTC should have been returned for an invalid time zone"
] ]
yield test "localTimeNow fails when clock is not passed" { yield test "LocalTimeNow fails when clock is not passed" {
Expect.throws (fun () -> (SmallGroup.empty.localTimeNow >> ignore) null) Expect.throws (fun () -> (SmallGroup.empty.LocalTimeNow >> ignore) null)
"Should have raised an exception for null clock" "Should have raised an exception for null clock"
} }
yield test "localDateNow returns the date portion" { yield test "LocalDateNow returns the date portion" {
let now' = DateTime (2017, 5, 12, 1, 15, 0, DateTimeKind.Utc) let now' = DateTime (2017, 5, 12, 1, 15, 0, DateTimeKind.Utc)
let clock = FakeClock (Instant.FromDateTimeUtc now') let clock = FakeClock (Instant.FromDateTimeUtc now')
Expect.isLessThan (SmallGroup.empty.localDateNow clock) now.Date "The date should have been a day earlier" Expect.isLessThan (SmallGroup.empty.LocalDateNow clock) now.Date "The date should have been a day earlier"
} }
] ]
@ -362,9 +362,9 @@ let userTests =
Expect.isNotNull mt.SmallGroups "The small groups navigation property should not have been null" Expect.isNotNull mt.SmallGroups "The small groups navigation property should not have been null"
Expect.isEmpty mt.SmallGroups "There should be no small groups for an empty user" Expect.isEmpty mt.SmallGroups "There should be no small groups for an empty user"
} }
test "fullName concatenates first and last names" { test "Name concatenates first and last names" {
let user = { User.empty with FirstName = "Unit"; LastName = "Test" } let user = { User.empty with FirstName = "Unit"; LastName = "Test" }
Expect.equal user.fullName "Unit Test" "The full name should be the first and last, separated by a space" Expect.equal user.Name "Unit Test" "The full name should be the first and last, separated by a space"
} }
] ]

View File

@ -118,7 +118,6 @@ let appViewInfoTests =
test "fresh is constructed properly" { test "fresh is constructed properly" {
let vi = AppViewInfo.fresh let vi = AppViewInfo.fresh
Expect.isEmpty vi.Style "There should have been no styles set" Expect.isEmpty vi.Style "There should have been no styles set"
Expect.isEmpty vi.Script "There should have been no scripts set"
Expect.isNone vi.HelpLink "The help link should have been set to none" Expect.isNone vi.HelpLink "The help link should have been set to none"
Expect.isEmpty vi.Messages "There should have been no messages set" Expect.isEmpty vi.Messages "There should have been no messages set"
Expect.equal vi.Version "" "The version should have been blank" Expect.equal vi.Version "" "The version should have been blank"
@ -135,7 +134,7 @@ let assignGroupsTests =
let usr = { User.empty with Id = (Guid.NewGuid >> UserId) (); FirstName = "Alice"; LastName = "Bob" } let usr = { User.empty with Id = (Guid.NewGuid >> UserId) (); FirstName = "Alice"; LastName = "Bob" }
let asg = AssignGroups.fromUser usr let asg = AssignGroups.fromUser usr
Expect.equal asg.UserId (shortGuid usr.Id.Value) "The user ID was not filled correctly" Expect.equal asg.UserId (shortGuid usr.Id.Value) "The user ID was not filled correctly"
Expect.equal asg.UserName usr.fullName "The user name was not filled correctly" Expect.equal asg.UserName usr.Name "The user's name was not filled correctly"
Expect.equal asg.SmallGroups "" "The small group string was not filled correctly" Expect.equal asg.SmallGroups "" "The small group string was not filled correctly"
} }
] ]
@ -150,7 +149,7 @@ let editChurchTests =
Name = "Unit Test" Name = "Unit Test"
City = "Testlandia" City = "Testlandia"
State = "UT" State = "UT"
HasInterface = true HasVpsInterface = true
InterfaceAddress = Some "https://test-dem-units.test" InterfaceAddress = Some "https://test-dem-units.test"
} }
let edit = EditChurch.fromChurch church let edit = EditChurch.fromChurch church
@ -159,7 +158,7 @@ let editChurchTests =
Expect.equal edit.City church.City "The church's city was not filled correctly" Expect.equal edit.City church.City "The church's city was not filled correctly"
Expect.equal edit.State church.State "The church's state was not filled correctly" Expect.equal edit.State church.State "The church's state was not filled correctly"
Expect.isSome edit.HasInterface "The church should show that it has an interface" Expect.isSome edit.HasInterface "The church should show that it has an interface"
Expect.equal edit.HasInterface (Some true) "The hasInterface flag should be true" Expect.equal edit.HasInterface (Some true) "The HasVpsInterface flag should be true"
Expect.isSome edit.InterfaceAddress "The interface address should exist" Expect.isSome edit.InterfaceAddress "The interface address should exist"
Expect.equal edit.InterfaceAddress church.InterfaceAddress "The interface address was not filled correctly" Expect.equal edit.InterfaceAddress church.InterfaceAddress "The interface address was not filled correctly"
} }
@ -206,7 +205,7 @@ let editChurchTests =
Expect.equal church.Name edit.Name "The church name was not updated correctly" Expect.equal church.Name edit.Name "The church name was not updated correctly"
Expect.equal church.City edit.City "The church's city was not updated correctly" Expect.equal church.City edit.City "The church's city was not updated correctly"
Expect.equal church.State edit.State "The church's state was not updated correctly" Expect.equal church.State edit.State "The church's state was not updated correctly"
Expect.isTrue church.HasInterface "The church should show that it has an interface" Expect.isTrue church.HasVpsInterface "The church should show that it has an interface"
Expect.isSome church.InterfaceAddress "The interface address should exist" Expect.isSome church.InterfaceAddress "The interface address should exist"
Expect.equal church.InterfaceAddress edit.InterfaceAddress "The interface address was not updated correctly" Expect.equal church.InterfaceAddress edit.InterfaceAddress "The interface address was not updated correctly"
} }
@ -217,7 +216,7 @@ let editChurchTests =
City = "Testerville" City = "Testerville"
State = "TE" State = "TE"
}.PopulateChurch Church.empty }.PopulateChurch Church.empty
Expect.isFalse church.HasInterface "The church should show that it has an interface" Expect.isFalse church.HasVpsInterface "The church should show that it has an interface"
Expect.isNone church.InterfaceAddress "The interface address should exist" Expect.isNone church.InterfaceAddress "The interface address should exist"
} }
] ]
@ -284,7 +283,7 @@ let editPreferencesTests =
Expect.equal edit.TimeZone (TimeZoneId.toString prefs.TimeZoneId) "The time zone was not filled correctly" Expect.equal edit.TimeZone (TimeZoneId.toString prefs.TimeZoneId) "The time zone was not filled correctly"
Expect.isSome edit.GroupPassword "The group password should have been set" Expect.isSome edit.GroupPassword "The group password should have been set"
Expect.equal edit.GroupPassword (Some prefs.GroupPassword) "The group password was not filled correctly" Expect.equal edit.GroupPassword (Some prefs.GroupPassword) "The group password was not filled correctly"
Expect.equal edit.Visibility RequestVisibility.``private`` Expect.equal edit.Visibility GroupVisibility.PrivateList
"The list visibility was not derived correctly" "The list visibility was not derived correctly"
Expect.equal edit.PageSize prefs.PageSize "The page size was not filled correctly" Expect.equal edit.PageSize prefs.PageSize "The page size was not filled correctly"
Expect.equal edit.AsOfDate (AsOfDateDisplay.toCode prefs.AsOfDateDisplay) Expect.equal edit.AsOfDate (AsOfDateDisplay.toCode prefs.AsOfDateDisplay)
@ -297,7 +296,7 @@ let editPreferencesTests =
Expect.equal edit.LineColor prefs.LineColor "The heading line color was not filled correctly" Expect.equal edit.LineColor prefs.LineColor "The heading line color was not filled correctly"
Expect.isSome edit.GroupPassword "The group password should have been set" Expect.isSome edit.GroupPassword "The group password should have been set"
Expect.equal edit.GroupPassword (Some prefs.GroupPassword) "The group password was not filled correctly" Expect.equal edit.GroupPassword (Some prefs.GroupPassword) "The group password was not filled correctly"
Expect.equal edit.Visibility RequestVisibility.passwordProtected Expect.equal edit.Visibility GroupVisibility.HasPassword
"The list visibility was not derived correctly" "The list visibility was not derived correctly"
} }
test "fromPreferences succeeds for RGB text color and public list" { test "fromPreferences succeeds for RGB text color and public list" {
@ -307,7 +306,7 @@ let editPreferencesTests =
Expect.equal edit.HeadingColor prefs.HeadingColor "The heading text color was not filled correctly" Expect.equal edit.HeadingColor prefs.HeadingColor "The heading text color was not filled correctly"
Expect.isSome edit.GroupPassword "The group password should have been set" Expect.isSome edit.GroupPassword "The group password should have been set"
Expect.equal edit.GroupPassword (Some "") "The group password was not filled correctly" Expect.equal edit.GroupPassword (Some "") "The group password was not filled correctly"
Expect.equal edit.Visibility RequestVisibility.``public`` Expect.equal edit.Visibility GroupVisibility.PublicList
"The list visibility was not derived correctly" "The list visibility was not derived correctly"
} }
] ]

View File

@ -84,7 +84,7 @@ let maintain (churches : Church list) (stats : Map<string, ChurchStats>) ctx vi
td [ _class "pt-right-text" ] [ rawText (stats[chId].SmallGroups.ToString "N0") ] td [ _class "pt-right-text" ] [ rawText (stats[chId].SmallGroups.ToString "N0") ]
td [ _class "pt-right-text" ] [ rawText (stats[chId].PrayerRequests.ToString "N0") ] td [ _class "pt-right-text" ] [ rawText (stats[chId].PrayerRequests.ToString "N0") ]
td [ _class "pt-right-text" ] [ rawText (stats[chId].Users.ToString "N0") ] td [ _class "pt-right-text" ] [ rawText (stats[chId].Users.ToString "N0") ]
td [ _class "pt-center-text" ] [ locStr s[if ch.HasInterface then "Yes" else "No"] ] td [ _class "pt-center-text" ] [ locStr s[if ch.HasVpsInterface then "Yes" else "No"] ]
]) ])
|> tbody [] |> tbody []
] ]

View File

@ -159,7 +159,7 @@ module Navigation =
span [ _class "u" ] [ locStr s["Currently Logged On"] ] span [ _class "u" ] [ locStr s["Currently Logged On"] ]
rawText "&nbsp; &nbsp;" rawText "&nbsp; &nbsp;"
icon "person" icon "person"
strong [] [ str u.fullName ] strong [] [ str u.Name ]
rawText "&nbsp; &nbsp; " rawText "&nbsp; &nbsp; "
| None -> | None ->
locStr s["Logged On as a Member of"] locStr s["Logged On as a Member of"]
@ -169,7 +169,6 @@ module Navigation =
match m.User with match m.User with
| Some _ -> a [ _href "/small-group"; Target.content ] [ strong [] [ str g.Name ] ] | Some _ -> a [ _href "/small-group"; Target.content ] [ strong [] [ str g.Name ] ]
| None -> strong [] [ str g.Name ] | None -> strong [] [ str g.Name ]
rawText " &nbsp;"
] ]
| None -> [] | None -> []
|> div [] |> div []
@ -263,12 +262,12 @@ let private htmlFooter viewInfo =
let s = I18N.localizer.Force () let s = I18N.localizer.Force ()
let imgText = $"""%O{s["PrayerTracker"]} %O{s["from Bit Badger Solutions"]}""" let imgText = $"""%O{s["PrayerTracker"]} %O{s["from Bit Badger Solutions"]}"""
let resultTime = TimeSpan(DateTime.Now.Ticks - viewInfo.RequestStart).TotalSeconds let resultTime = TimeSpan(DateTime.Now.Ticks - viewInfo.RequestStart).TotalSeconds
footer [] [ footer [ _class "pt-footer" ] [
div [ _id "pt-legal" ] [ div [ _id "pt-legal" ] [
a [ _href "/legal/privacy-policy" ] [ locStr s["Privacy Policy"] ] a [ _href "/legal/privacy-policy" ] [ locStr s["Privacy Policy"] ]
rawText " &bull; " rawText " &nbsp; "
a [ _href "/legal/terms-of-service" ] [ locStr s["Terms of Service"] ] a [ _href "/legal/terms-of-service" ] [ locStr s["Terms of Service"] ]
rawText " &bull; " rawText " &nbsp; "
a [ _href "https://github.com/bit-badger/PrayerTracker" a [ _href "https://github.com/bit-badger/PrayerTracker"
_title s["View source code and get technical support"].Value _title s["View source code and get technical support"].Value
_target "_blank" _target "_blank"
@ -278,7 +277,10 @@ let private htmlFooter viewInfo =
] ]
div [ _id "pt-footer" ] [ div [ _id "pt-footer" ] [
a [ _href "/"; _style "line-height:28px;" ] [ a [ _href "/"; _style "line-height:28px;" ] [
img [ _src $"""/img/%O{s["footer_en"]}.png"""; _alt imgText; _title imgText ] img [ _src $"""/img/%O{s["footer_en"]}.png"""
_alt imgText
_title imgText
_width "331"; _height "28" ]
] ]
str viewInfo.Version str viewInfo.Version
space space
@ -286,8 +288,6 @@ let private htmlFooter viewInfo =
str "schedule" str "schedule"
] ]
] ]
Script.minified
script [ _src "/js/app.js" ] []
] ]
/// The content portion of the PrayerTracker layout /// The content portion of the PrayerTracker layout
@ -297,13 +297,21 @@ let private contentSection viewInfo pgTitle (content : XmlNode) = [
yield! messages viewInfo yield! messages viewInfo
match viewInfo.ScopedStyle with match viewInfo.ScopedStyle with
| [] -> () | [] -> ()
| styles -> style [ _scoped ] (styles |> List.map (fun it -> rawText $"{it}; ")) | styles -> style [] [ rawText (styles |> String.concat " ") ]
content content
htmlFooter viewInfo htmlFooter viewInfo
for jsFile in viewInfo.Script do
script [ _src $"/js/{jsFile}.js" ] []
match viewInfo.OnLoadScript with match viewInfo.OnLoadScript with
| Some onLoad -> script [] [ rawText $"{onLoad}()" ] | Some onLoad ->
script [] [
rawText $"""
window.doOnLoad = () => {{
if (window.PT) {{
{onLoad}()
delete window.doOnLoad
}} else {{ setTimeout(window.doOnLoad, 500) }}
}}
window.doOnLoad()"""
]
| None -> () | None -> ()
] ]
@ -323,6 +331,12 @@ let private pageLayout viewInfo pgTitle content =
Navigation.top viewInfo Navigation.top viewInfo
div [ _id "pt-body"; Target.content; _hxSwap $"{HxSwap.InnerHtml} show:window:top" ] div [ _id "pt-body"; Target.content; _hxSwap $"{HxSwap.InnerHtml} show:window:top" ]
(contentSection viewInfo pgTitle content) (contentSection viewInfo pgTitle content)
match viewInfo.Layout with
| FullPage ->
Script.minified
script [ _src "/js/ckeditor/ckeditor.js" ] []
script [ _src "/js/app.js" ] []
| _ -> ()
] ]
/// The standard layout(s) for PrayerTracker /// The standard layout(s) for PrayerTracker

View File

@ -152,14 +152,14 @@ let maintain (model : MaintainRequests) (ctx : HttpContext) viewInfo =
let l = I18N.forView "Requests/Maintain" let l = I18N.forView "Requests/Maintain"
use sw = new StringWriter () use sw = new StringWriter ()
let raw = rawLocText sw let raw = rawLocText sw
let now = model.SmallGroup.localDateNow (ctx.GetService<IClock> ()) let now = model.SmallGroup.LocalDateNow (ctx.GetService<IClock> ())
let prefs = model.SmallGroup.Preferences let prefs = model.SmallGroup.Preferences
let types = ReferenceList.requestTypeList s |> Map.ofList let types = ReferenceList.requestTypeList s |> Map.ofList
let updReq (req : PrayerRequest) = let updReq (req : PrayerRequest) =
if req.updateRequired now prefs.DaysToExpire prefs.LongTermUpdateWeeks then "pt-request-update" else "" if req.UpdateRequired now prefs.DaysToExpire prefs.LongTermUpdateWeeks then "pt-request-update" else ""
|> _class |> _class
let reqExp (req : PrayerRequest) = let reqExp (req : PrayerRequest) =
_class (if req.isExpired now prefs.DaysToExpire then "pt-request-expired" else "") _class (if req.IsExpired now prefs.DaysToExpire then "pt-request-expired" else "")
/// Iterate the sequence once, before we render, so we can get the count of it at the top of the table /// Iterate the sequence once, before we render, so we can get the count of it at the top of the table
let requests = let requests =
model.Requests model.Requests
@ -180,7 +180,7 @@ let maintain (model : MaintainRequests) (ctx : HttpContext) viewInfo =
a [ _href $"/prayer-request/{reqId}/edit"; _title l["Edit This Prayer Request"].Value ] [ a [ _href $"/prayer-request/{reqId}/edit"; _title l["Edit This Prayer Request"].Value ] [
icon "edit" icon "edit"
] ]
if req.isExpired now prefs.DaysToExpire then if req.IsExpired now prefs.DaysToExpire then
a [ _href $"/prayer-request/{reqId}/restore" a [ _href $"/prayer-request/{reqId}/restore"
_title l["Restore This Inactive Request"].Value ] [ _title l["Restore This Inactive Request"].Value ] [
icon "visibility" icon "visibility"
@ -305,39 +305,40 @@ let view model viewInfo =
let pageTitle = $"""{s["Prayer Requests"].Value} {model.SmallGroup.Name}""" let pageTitle = $"""{s["Prayer Requests"].Value} {model.SmallGroup.Name}"""
let spacer = rawText " &nbsp; &nbsp; &nbsp; " let spacer = rawText " &nbsp; &nbsp; &nbsp; "
let dtString = model.Date.ToString "yyyy-MM-dd" let dtString = model.Date.ToString "yyyy-MM-dd"
div [ _class "pt-center-text" ] [ [ div [ _class "pt-center-text" ] [
br [] br []
a [ _class "pt-icon-link" a [ _class "pt-icon-link"
_href $"/prayer-requests/print/{dtString}" _href $"/prayer-requests/print/{dtString}"
_target "_blank" _target "_blank"
_title s["View Printable"].Value ] [ _title s["View Printable"].Value ] [
icon "print"; rawText " &nbsp;"; locStr s["View Printable"] icon "print"; rawText " &nbsp;"; locStr s["View Printable"]
] ]
if model.CanEmail then if model.CanEmail then
spacer spacer
if model.Date.DayOfWeek <> DayOfWeek.Sunday then if model.Date.DayOfWeek <> DayOfWeek.Sunday then
let rec findSunday (date : DateTime) = let rec findSunday (date : DateTime) =
if date.DayOfWeek = DayOfWeek.Sunday then date else findSunday (date.AddDays 1.) if date.DayOfWeek = DayOfWeek.Sunday then date else findSunday (date.AddDays 1.)
let sunday = findSunday model.Date let sunday = findSunday model.Date
a [ _class "pt-icon-link" a [ _class "pt-icon-link"
_href $"""/prayer-requests/view/{sunday.ToString "yyyy-MM-dd"}""" _href $"""/prayer-requests/view/{sunday.ToString "yyyy-MM-dd"}"""
_title s["List for Next Sunday"].Value ] [ _title s["List for Next Sunday"].Value ] [
icon "update"; rawText " &nbsp;"; locStr s["List for Next Sunday"] icon "update"; rawText " &nbsp;"; locStr s["List for Next Sunday"]
] ]
spacer spacer
let emailPrompt = s["This will e-mail the current list to every member of your group, without further prompting. Are you sure this is what you are ready to do?"].Value let emailPrompt = s["This will e-mail the current list to every member of your group, without further prompting. Are you sure this is what you are ready to do?"].Value
a [ _class "pt-icon-link" a [ _class "pt-icon-link"
_href $"/prayer-requests/email/{dtString}" _href $"/prayer-requests/email/{dtString}"
_title s["Send via E-mail"].Value _title s["Send via E-mail"].Value
_onclick $"return PT.requests.view.promptBeforeEmail('{emailPrompt}')" ] [ _onclick $"return PT.requests.view.promptBeforeEmail('{emailPrompt}')" ] [
icon "mail_outline"; rawText " &nbsp;"; locStr s["Send via E-mail"] icon "mail_outline"; rawText " &nbsp;"; locStr s["Send via E-mail"]
]
spacer
a [ _class "pt-icon-link"; _href "/prayer-requests"; _title s["Maintain Prayer Requests"].Value ] [
icon "compare_arrows"; rawText " &nbsp;"; locStr s["Maintain Prayer Requests"]
] ]
spacer
a [ _class "pt-icon-link"; _href "/prayer-requests"; _title s["Maintain Prayer Requests"].Value ] [
icon "compare_arrows"; rawText " &nbsp;"; locStr s["Maintain Prayer Requests"]
] ]
br []
rawText (model.AsHtml s)
] ]
|> List.singleton
|> List.append [ br []; rawText (model.AsHtml s) ]
|> Layout.Content.standard |> Layout.Content.standard
|> Layout.standard viewInfo pageTitle |> Layout.standard viewInfo pageTitle

View File

@ -349,200 +349,199 @@ let preferences (model : EditPreferences) (tzs : TimeZone list) ctx viewInfo =
$"@media screen and (max-width: 40rem) {{ {fontsId} {{ width: 100%%; }} }}" $"@media screen and (max-width: 40rem) {{ {fontsId} {{ width: 100%%; }} }}"
] ]
|> AppViewInfo.withOnLoadScript "PT.smallGroup.preferences.onPageLoad" |> AppViewInfo.withOnLoadScript "PT.smallGroup.preferences.onPageLoad"
form [ _action "/small-group/preferences/save"; _method "post"; _class "pt-center-columns"; Target.content ] [ [ form [ _action "/small-group/preferences/save"; _method "post"; _class "pt-center-columns"; Target.content ] [
csrfToken ctx csrfToken ctx
fieldset [] [ fieldset [] [
legend [] [ strong [] [ icon "date_range"; rawText " &nbsp;"; locStr s["Dates"] ] ] legend [] [ strong [] [ icon "date_range"; rawText " &nbsp;"; locStr s["Dates"] ] ]
div [ _fieldRow ] [ div [ _fieldRow ] [
div [ _inputField ] [ div [ _inputField ] [
label [ _for (nameof model.ExpireDays) ] [ locStr s["Requests Expire After"] ] label [ _for (nameof model.ExpireDays) ] [ locStr s["Requests Expire After"] ]
span [] [ span [] [
inputField "number" (nameof model.ExpireDays) (string model.ExpireDays) [ inputField "number" (nameof model.ExpireDays) (string model.ExpireDays) [
_min "1"; _max "30"; _required; _autofocus _min "1"; _max "30"; _required; _autofocus
]
space
str (s["Days"].Value.ToLower ())
] ]
space
str (s["Days"].Value.ToLower ())
] ]
] div [ _inputField ] [
div [ _inputField ] [ label [ _for (nameof model.DaysToKeepNew) ] [ locStr s["Requests “New” For"] ]
label [ _for (nameof model.DaysToKeepNew) ] [ locStr s["Requests “New” For"] ] span [] [
span [] [ inputField "number" (nameof model.DaysToKeepNew) (string model.DaysToKeepNew) [
inputField "number" (nameof model.DaysToKeepNew) (string model.DaysToKeepNew) [ _min "1"; _max "30"; _required
_min "1"; _max "30"; _required ]
space; str (s["Days"].Value.ToLower ())
] ]
space; str (s["Days"].Value.ToLower ())
] ]
] div [ _inputField ] [
div [ _inputField ] [ label [ _for (nameof model.LongTermUpdateWeeks) ] [
label [ _for (nameof model.LongTermUpdateWeeks) ] [ locStr s["Long-Term Requests Alerted for Update"]
locStr s["Long-Term Requests Alerted for Update"] ]
] span [] [
span [] [ inputField "number" (nameof model.LongTermUpdateWeeks) (string model.LongTermUpdateWeeks) [
inputField "number" (nameof model.LongTermUpdateWeeks) (string model.LongTermUpdateWeeks) [ _min "1"; _max "30"; _required
_min "1"; _max "30"; _required ]
space; str (s["Weeks"].Value.ToLower ())
] ]
space; str (s["Weeks"].Value.ToLower ())
] ]
] ]
] ]
] fieldset [] [
fieldset [] [ legend [] [ strong [] [ icon "sort"; rawText " &nbsp;"; locStr s["Request Sorting"] ] ]
legend [] [ strong [] [ icon "sort"; rawText " &nbsp;"; locStr s["Request Sorting"] ] ] radio (nameof model.RequestSort) $"{nameof model.RequestSort}_D" "D" model.RequestSort
radio (nameof model.RequestSort) $"{nameof model.RequestSort}_D" "D" model.RequestSort label [ _for $"{nameof model.RequestSort}_D" ] [ locStr s["Sort by Last Updated Date"] ]
label [ _for $"{nameof model.RequestSort}_D" ] [ locStr s["Sort by Last Updated Date"] ] rawText " &nbsp; "
rawText " &nbsp; " radio (nameof model.RequestSort) $"{nameof model.RequestSort}_R" "R" model.RequestSort
radio (nameof model.RequestSort) $"{nameof model.RequestSort}_R" "R" model.RequestSort label [ _for $"{nameof model.RequestSort}_R" ] [ locStr s["Sort by Requestor Name"] ]
label [ _for $"{nameof model.RequestSort}_R" ] [ locStr s["Sort by Requestor Name"] ] ]
] fieldset [] [
fieldset [] [ legend [] [ strong [] [ icon "mail_outline"; rawText " &nbsp;"; locStr s["E-mail"] ] ]
legend [] [ strong [] [ icon "mail_outline"; rawText " &nbsp;"; locStr s["E-mail"] ] ] div [ _fieldRow ] [
div [ _fieldRow ] [ div [ _inputField ] [
div [ _inputField ] [ label [ _for (nameof model.EmailFromName) ] [ locStr s["From Name"] ]
label [ _for (nameof model.EmailFromName) ] [ locStr s["From Name"] ] inputField "text" (nameof model.EmailFromName) model.EmailFromName [ _required ]
inputField "text" (nameof model.EmailFromName) model.EmailFromName [ _required ] ]
div [ _inputField ] [
label [ _for (nameof model.EmailFromAddress) ] [ locStr s["From Address"] ]
inputField "email" (nameof model.EmailFromAddress) model.EmailFromAddress [ _required ]
]
] ]
div [ _inputField ] [ div [ _fieldRow ] [
label [ _for (nameof model.EmailFromAddress) ] [ locStr s["From Address"] ] div [ _inputField ] [
inputField "email" (nameof model.EmailFromAddress) model.EmailFromAddress [ _required ] label [ _for (nameof model.DefaultEmailType) ] [ locStr s["E-mail Format"] ]
seq {
"", selectDefault s["Select"].Value
yield!
ReferenceList.emailTypeList HtmlFormat s
|> Seq.skip 1
|> Seq.map (fun typ -> fst typ, (snd typ).Value)
}
|> selectList (nameof model.DefaultEmailType) model.DefaultEmailType [ _required ]
]
] ]
] ]
div [ _fieldRow ] [ fieldset [] [
div [ _inputField ] [ legend [] [ strong [] [ icon "color_lens"; rawText " &nbsp;"; locStr s["Colors"] ]; rawText " ***" ]
label [ _for (nameof model.DefaultEmailType) ] [ locStr s["E-mail Format"] ] div [ _fieldRow ] [
seq { div [ _inputField ] [
"", selectDefault s["Select"].Value label [ _class "pt-center-text" ] [ locStr s["Color of Heading Lines"] ]
yield! span [] [
ReferenceList.emailTypeList HtmlFormat s radio (nameof model.LineColorType) $"{nameof model.LineColorType}_Name" "Name"
|> Seq.skip 1 model.LineColorType
|> Seq.map (fun typ -> fst typ, (snd typ).Value) label [ _for $"{nameof model.LineColorType}_Name" ] [ locStr s["Named Color"] ]
} namedColorList (nameof model.LineColor) model.LineColor [
|> selectList (nameof model.DefaultEmailType) model.DefaultEmailType [ _required ] _id $"{nameof model.LineColor}_Select"
if model.LineColor.StartsWith "#" then _disabled ] s
rawText "&nbsp; &nbsp; "; str (s["or"].Value.ToUpper ())
radio (nameof model.LineColorType) $"{nameof model.LineColorType}_RGB" "RGB"
model.LineColorType
label [ _for $"{nameof model.LineColorType}_RGB" ] [ locStr s["Custom Color"] ]
input [ _type "color"
_name (nameof model.LineColor)
_id $"{nameof model.LineColor}_Color"
_value model.LineColor // TODO: convert to hex or skip if named
if not (model.LineColor.StartsWith "#") then _disabled ]
]
]
]
div [ _fieldRow ] [
div [ _inputField ] [
label [ _class "pt-center-text" ] [ locStr s["Color of Heading Text"] ]
span [] [
radio (nameof model.HeadingColorType) $"{nameof model.HeadingColorType}_Name" "Name"
model.HeadingColorType
label [ _for $"{nameof model.HeadingColorType}_Name" ] [ locStr s["Named Color"] ]
namedColorList (nameof model.HeadingColor) model.HeadingColor [
_id $"{nameof model.HeadingColor}_Select"
if model.HeadingColor.StartsWith "#" then _disabled ] s
rawText "&nbsp; &nbsp; "; str (s["or"].Value.ToUpper ())
radio (nameof model.HeadingColorType) $"{nameof model.HeadingColorType}_RGB" "RGB"
model.HeadingColorType
label [ _for $"{nameof model.HeadingColorType}_RGB" ] [ locStr s["Custom Color"] ]
input [ _type "color"
_name (nameof model.HeadingColor)
_id $"{nameof model.HeadingColor}_Color"
_value model.HeadingColor // TODO: convert to hex or skip if named
if not (model.HeadingColor.StartsWith "#") then _disabled ]
]
]
] ]
] ]
] fieldset [] [
fieldset [] [ legend [] [ strong [] [ icon "font_download"; rawText " &nbsp;"; locStr s["Fonts"] ] ]
legend [] [ strong [] [ icon "color_lens"; rawText " &nbsp;"; locStr s["Colors"] ]; rawText " ***" ]
div [ _fieldRow ] [
div [ _inputField ] [ div [ _inputField ] [
label [ _class "pt-center-text" ] [ locStr s["Color of Heading Lines"] ] label [ _for (nameof model.Fonts) ] [ locStr s["Fonts** for List"] ]
inputField "text" (nameof model.Fonts) model.Fonts [ _required ]
]
div [ _fieldRow ] [
div [ _inputField ] [
label [ _for (nameof model.HeadingFontSize) ] [ locStr s["Heading Text Size"] ]
inputField "number" (nameof model.HeadingFontSize) (string model.HeadingFontSize) [
_min "8"; _max "24"; _required
]
]
div [ _inputField ] [
label [ _for (nameof model.ListFontSize) ] [ locStr s["List Text Size"] ]
inputField "number" (nameof model.ListFontSize) (string model.ListFontSize) [
_min "8"; _max "24"; _required
]
]
]
]
fieldset [] [
legend [] [ strong [] [ icon "settings"; rawText " &nbsp;"; locStr s["Other Settings"] ] ]
div [ _fieldRow ] [
div [ _inputField ] [
label [ _for (nameof model.TimeZone) ] [ locStr s["Time Zone"] ]
seq {
"", selectDefault s["Select"].Value
yield!
tzs
|> List.map (fun tz ->
TimeZoneId.toString tz.Id, (TimeZones.name tz.Id s).Value)
}
|> selectList (nameof model.TimeZone) model.TimeZone [ _required ]
]
]
div [ _inputField ] [
label [] [ locStr s["Request List Visibility"] ]
span [] [ span [] [
radio (nameof model.LineColorType) $"{nameof model.LineColorType}_Name" "Name" let name = nameof model.Visibility
model.LineColorType let value = string model.Visibility
label [ _for $"{nameof model.LineColorType}_Name" ] [ locStr s["Named Color"] ] radio name $"{name}_Public" (string GroupVisibility.PublicList) value
namedColorList (nameof model.LineColor) model.LineColor [ label [ _for $"{name}_Public" ] [ locStr s["Public"] ]
_id $"{nameof model.LineColor}_Select" rawText " &nbsp;"
if model.LineColor.StartsWith "#" then _disabled ] s radio name $"{name}_Private" (string GroupVisibility.PrivateList) value
rawText "&nbsp; &nbsp; "; str (s["or"].Value.ToUpper ()) label [ _for $"{name}_Private" ] [ locStr s["Private"] ]
radio (nameof model.LineColorType) $"{nameof model.LineColorType}_RGB" "RGB" model.LineColorType rawText " &nbsp;"
label [ _for $"{nameof model.LineColorType}_RGB" ] [ locStr s["Custom Color"] ] radio name $"{name}_Password" (string GroupVisibility.HasPassword) value
input [ _type "color" label [ _for $"{name}_Password" ] [ locStr s["Password Protected"] ]
_name (nameof model.LineColor) ]
_id $"{nameof model.LineColor}_Color" ]
_value model.LineColor // TODO: convert to hex or skip if named let classSuffix = if model.Visibility = GroupVisibility.HasPassword then [ "pt-show" ] else []
if not (model.LineColor.StartsWith "#") then _disabled ] div [ _id "divClassPassword"; _fieldRowWith ("pt-fadeable" :: classSuffix) ] [
] div [ _inputField ] [
] label [ _for (nameof model.GroupPassword) ] [ locStr s["Group Password (Used to Read Online)"] ]
] inputField "text" (nameof model.GroupPassword) (defaultArg model.GroupPassword "") []
div [ _fieldRow ] [ ]
div [ _inputField ] [ ]
label [ _class "pt-center-text" ] [ locStr s["Color of Heading Text"] ] div [ _fieldRow ] [
span [] [ div [ _inputField ] [
radio (nameof model.HeadingColorType) $"{nameof model.HeadingColorType}_Name" "Name" label [ _for (nameof model.PageSize) ] [ locStr s["Page Size"] ]
model.HeadingColorType inputField "number" (nameof model.PageSize) (string model.PageSize) [
label [ _for $"{nameof model.HeadingColorType}_Name" ] [ locStr s["Named Color"] ] _min "10"; _max "255"; _required
namedColorList (nameof model.HeadingColor) model.HeadingColor [ ]
_id $"{nameof model.HeadingColor}_Select" ]
if model.HeadingColor.StartsWith "#" then _disabled ] s div [ _inputField ] [
rawText "&nbsp; &nbsp; "; str (s["or"].Value.ToUpper ()) label [ _for (nameof model.AsOfDate) ] [ locStr s["“As of” Date Display"] ]
radio (nameof model.HeadingColorType) $"{nameof model.HeadingColorType}_RGB" "RGB" ReferenceList.asOfDateList s
model.HeadingColorType |> List.map (fun (code, desc) -> code, desc.Value)
label [ _for $"{nameof model.HeadingColorType}_RGB" ] [ locStr s["Custom Color"] ] |> selectList (nameof model.AsOfDate) model.AsOfDate [ _required ]
input [ _type "color"
_name (nameof model.HeadingColor)
_id $"{nameof model.HeadingColor}_Color"
_value model.HeadingColor // TODO: convert to hex or skip if named
if not (model.HeadingColor.StartsWith "#") then _disabled ]
] ]
] ]
] ]
div [ _fieldRow ] [ submit [] "save" s["Save Preferences"] ]
] ]
fieldset [] [
legend [] [ strong [] [ icon "font_download"; rawText " &nbsp;"; locStr s["Fonts"] ] ]
div [ _inputField ] [
label [ _for (nameof model.Fonts) ] [ locStr s["Fonts** for List"] ]
inputField "text" (nameof model.Fonts) model.Fonts [ _required ]
]
div [ _fieldRow ] [
div [ _inputField ] [
label [ _for (nameof model.HeadingFontSize) ] [ locStr s["Heading Text Size"] ]
inputField "number" (nameof model.HeadingFontSize) (string model.HeadingFontSize) [
_min "8"; _max "24"; _required
]
]
div [ _inputField ] [
label [ _for (nameof model.ListFontSize) ] [ locStr s["List Text Size"] ]
inputField "number" (nameof model.ListFontSize) (string model.ListFontSize) [
_min "8"; _max "24"; _required
]
]
]
]
fieldset [] [
legend [] [ strong [] [ icon "settings"; rawText " &nbsp;"; locStr s["Other Settings"] ] ]
div [ _fieldRow ] [
div [ _inputField ] [
label [ _for (nameof model.TimeZone) ] [ locStr s["Time Zone"] ]
seq {
"", selectDefault s["Select"].Value
yield!
tzs
|> List.map (fun tz ->
TimeZoneId.toString tz.Id, (TimeZones.name tz.Id s).Value)
}
|> selectList (nameof model.TimeZone) model.TimeZone [ _required ]
]
]
div [ _inputField ] [
label [] [ locStr s["Request List Visibility"] ]
span [] [
let name = nameof model.Visibility
let value = string model.Visibility
radio name $"{name}_Public" (string RequestVisibility.``public``) value
label [ _for $"{name}_Public" ] [ locStr s["Public"] ]
rawText " &nbsp;"
radio name $"{name}_Private" (string RequestVisibility.``private``) value
label [ _for $"{name}_Private" ] [ locStr s["Private"] ]
rawText " &nbsp;"
radio name $"{name}_Password" (string RequestVisibility.passwordProtected) value
label [ _for $"{name}_Password" ] [ locStr s["Password Protected"] ]
]
]
let classSuffix = if model.Visibility = RequestVisibility.passwordProtected then [ "pt-show" ] else []
div [ _id "divClassPassword"; _fieldRowWith ("pt-fadeable" :: classSuffix) ] [
div [ _inputField ] [
label [ _for (nameof model.GroupPassword) ] [ locStr s["Group Password (Used to Read Online)"] ]
inputField "text" (nameof model.GroupPassword) (defaultArg model.GroupPassword "") []
]
]
div [ _fieldRow ] [
div [ _inputField ] [
label [ _for (nameof model.PageSize) ] [ locStr s["Page Size"] ]
inputField "number" (nameof model.PageSize) (string model.PageSize) [
_min "10"; _max "255"; _required
]
]
div [ _inputField ] [
label [ _for (nameof model.AsOfDate) ] [ locStr s["“As of” Date Display"] ]
ReferenceList.asOfDateList s
|> List.map (fun (code, desc) -> code, desc.Value)
|> selectList (nameof model.AsOfDate) model.AsOfDate [ _required ]
]
]
]
div [ _fieldRow ] [ submit [] "save" s["Save Preferences"] ]
]
|> List.singleton
|> List.append [
p [] [ p [] [
rawText "** " rawText "** "
raw l["List font names, separated by commas."] raw l["List font names, separated by commas."]

View File

@ -199,7 +199,7 @@ let maintain (users : User list) ctx viewInfo =
let userId = shortGuid user.Id.Value let userId = shortGuid user.Id.Value
let delAction = $"/user/{userId}/delete" let delAction = $"/user/{userId}/delete"
let delPrompt = s["Are you sure you want to delete this {0}? This action cannot be undone.", let delPrompt = s["Are you sure you want to delete this {0}? This action cannot be undone.",
$"""{s["User"].Value.ToLower ()} ({user.fullName})"""].Value $"""{s["User"].Value.ToLower ()} ({user.Name})"""].Value
tr [] [ tr [] [
td [] [ td [] [
a [ _href $"/user/{userId}/edit"; _title s["Edit This User"].Value ] [ icon "edit" ] a [ _href $"/user/{userId}/edit"; _title s["Edit This User"].Value ] [ icon "edit" ]
@ -212,7 +212,7 @@ let maintain (users : User list) ctx viewInfo =
icon "delete_forever" icon "delete_forever"
] ]
] ]
td [] [ str user.fullName ] td [] [ str user.Name ]
td [ _class "pt-center-text" ] [ td [ _class "pt-center-text" ] [
if user.IsAdmin then strong [] [ locStr s["Yes"] ] else locStr s["No"] if user.IsAdmin then strong [] [ locStr s["Yes"] ] else locStr s["No"]
] ]

View File

@ -175,19 +175,19 @@ module Key =
/// Enumerated values for small group request list visibility (derived from preferences, used in UI) /// Enumerated values for small group request list visibility (derived from preferences, used in UI)
module RequestVisibility = module GroupVisibility =
/// Requests are publicly accessible /// Requests are publicly accessible
[<Literal>] [<Literal>]
let ``public`` = 1 let PublicList = 1
/// The small group members can enter a password to view the request list /// The small group members can enter a password to view the request list
[<Literal>] [<Literal>]
let passwordProtected = 2 let HasPassword = 2
/// No one can see the requests for a small group except its administrators ("User" access level) /// No one can see the requests for a small group except its administrators ("User" access level)
[<Literal>] [<Literal>]
let ``private`` = 3 let PrivateList = 3
/// Links for help locations /// Links for help locations

View File

@ -124,9 +124,6 @@ type AppViewInfo =
{ /// CSS files for the page { /// CSS files for the page
Style : string list Style : string list
/// JavaScript files for the page
Script : string list
/// The link for help on this page /// The link for help on this page
HelpLink : string option HelpLink : string option
@ -162,7 +159,6 @@ module AppViewInfo =
/// A fresh version that can be populated to process the current request /// A fresh version that can be populated to process the current request
let fresh = let fresh =
{ Style = [] { Style = []
Script = []
HelpLink = None HelpLink = None
Messages = [] Messages = []
Version = "" Version = ""
@ -224,7 +220,7 @@ module AssignGroups =
/// Create an instance of this form from an existing user /// Create an instance of this form from an existing user
let fromUser (user : User) = let fromUser (user : User) =
{ UserId = shortGuid user.Id.Value { UserId = shortGuid user.Id.Value
UserName = user.fullName UserName = user.Name
SmallGroups = "" SmallGroups = ""
} }
@ -275,7 +271,7 @@ with
Name = this.Name Name = this.Name
City = this.City City = this.City
State = this.State State = this.State
HasInterface = match this.HasInterface with Some x -> x | None -> false HasVpsInterface = match this.HasInterface with Some x -> x | None -> false
InterfaceAddress = match this.HasInterface with Some x when x -> this.InterfaceAddress | _ -> None InterfaceAddress = match this.HasInterface with Some x when x -> this.InterfaceAddress | _ -> None
} }
@ -288,7 +284,7 @@ module EditChurch =
Name = church.Name Name = church.Name
City = church.City City = church.City
State = church.State State = church.State
HasInterface = match church.HasInterface with true -> Some true | false -> None HasInterface = match church.HasVpsInterface with true -> Some true | false -> None
InterfaceAddress = church.InterfaceAddress InterfaceAddress = church.InterfaceAddress
} }
@ -408,11 +404,9 @@ with
/// Set the properties of a small group based on the form's properties /// Set the properties of a small group based on the form's properties
member this.PopulatePreferences (prefs : ListPreferences) = member this.PopulatePreferences (prefs : ListPreferences) =
let isPublic, grpPw = let isPublic, grpPw =
match this.Visibility with if this.Visibility = GroupVisibility.PublicList then true, ""
| RequestVisibility.``public`` -> true, "" elif this.Visibility = GroupVisibility.HasPassword then false, (defaultArg this.GroupPassword "")
| RequestVisibility.passwordProtected -> false, (defaultArg this.GroupPassword "") else (* GroupVisibility.PrivateList *) false, ""
| RequestVisibility.``private``
| _ -> false, ""
{ prefs with { prefs with
DaysToExpire = this.ExpireDays DaysToExpire = this.ExpireDays
DaysToKeepNew = this.DaysToKeepNew DaysToKeepNew = this.DaysToKeepNew
@ -457,10 +451,9 @@ module EditPreferences =
PageSize = prefs.PageSize PageSize = prefs.PageSize
AsOfDate = AsOfDateDisplay.toCode prefs.AsOfDateDisplay AsOfDate = AsOfDateDisplay.toCode prefs.AsOfDateDisplay
Visibility = Visibility =
match true with if prefs.IsPublic then GroupVisibility.PublicList
| _ when prefs.IsPublic -> RequestVisibility.``public`` elif prefs.GroupPassword = "" then GroupVisibility.PrivateList
| _ when prefs.GroupPassword = "" -> RequestVisibility.``private`` else GroupVisibility.HasPassword
| _ -> RequestVisibility.passwordProtected
} }

View File

@ -1,10 +1,7 @@
module PrayerTracker.Handlers.PrayerRequest module PrayerTracker.Handlers.PrayerRequest
open System
open System.Threading.Tasks
open Giraffe open Giraffe
open Microsoft.AspNetCore.Http open Microsoft.AspNetCore.Http
open NodaTime
open PrayerTracker open PrayerTracker
open PrayerTracker.Entities open PrayerTracker.Entities
open PrayerTracker.ViewModels open PrayerTracker.ViewModels
@ -20,11 +17,13 @@ let private findRequest (ctx : HttpContext) reqId = task {
| None -> return Result.Error fourOhFour | None -> return Result.Error fourOhFour
} }
open NodaTime
/// Generate a list of requests for the given date /// Generate a list of requests for the given date
let private generateRequestList ctx date = task { let private generateRequestList ctx date = task {
let grp = currentGroup ctx let grp = currentGroup ctx
let clock = ctx.GetService<IClock> () let clock = ctx.GetService<IClock> ()
let listDate = match date with Some d -> d | None -> grp.localDateNow clock let listDate = match date with Some d -> d | None -> grp.LocalDateNow clock
let! reqs = ctx.db.AllRequestsForSmallGroup grp clock (Some listDate) true 0 let! reqs = ctx.db.AllRequestsForSmallGroup grp clock (Some listDate) true 0
return return
{ Requests = reqs { Requests = reqs
@ -36,29 +35,30 @@ let private generateRequestList ctx date = task {
} }
} }
open System
/// Parse a string into a date (optionally, of course) /// Parse a string into a date (optionally, of course)
let private parseListDate (date : string option) = let private parseListDate (date : string option) =
match date with match date with
| Some dt -> match DateTime.TryParse dt with true, d -> Some d | false, _ -> None | Some dt -> match DateTime.TryParse dt with true, d -> Some d | false, _ -> None
| None -> None | None -> None
/// GET /prayer-request/[request-id]/edit /// GET /prayer-request/[request-id]/edit
let edit reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task { let edit reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task {
let startTicks = DateTime.Now.Ticks let startTicks = DateTime.Now.Ticks
let grp = currentGroup ctx let grp = currentGroup ctx
let now = grp.localDateNow (ctx.GetService<IClock> ()) let now = grp.LocalDateNow (ctx.GetService<IClock> ())
let requestId = PrayerRequestId reqId let requestId = PrayerRequestId reqId
if requestId.Value = Guid.Empty then if requestId.Value = Guid.Empty then
return! return!
{ viewInfo ctx startTicks with Script = [ "ckeditor/ckeditor" ]; HelpLink = Some Help.editRequest } { viewInfo ctx startTicks with HelpLink = Some Help.editRequest }
|> Views.PrayerRequest.edit EditRequest.empty (now.ToString "yyyy-MM-dd") ctx |> Views.PrayerRequest.edit EditRequest.empty (now.ToString "yyyy-MM-dd") ctx
|> renderHtml next ctx |> renderHtml next ctx
else else
match! findRequest ctx requestId with match! findRequest ctx requestId with
| Ok req -> | Ok req ->
let s = Views.I18N.localizer.Force () let s = Views.I18N.localizer.Force ()
if req.isExpired now grp.Preferences.DaysToExpire then if req.IsExpired now grp.Preferences.DaysToExpire then
{ UserMessage.warning with { UserMessage.warning with
Text = htmlLocString s["This request is expired."] Text = htmlLocString s["This request is expired."]
Description = Description =
@ -68,13 +68,12 @@ let edit reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task {
} }
|> addUserMessage ctx |> addUserMessage ctx
return! return!
{ viewInfo ctx startTicks with Script = [ "ckeditor/ckeditor" ]; HelpLink = Some Help.editRequest } { viewInfo ctx startTicks with HelpLink = Some Help.editRequest }
|> Views.PrayerRequest.edit (EditRequest.fromRequest req) "" ctx |> Views.PrayerRequest.edit (EditRequest.fromRequest req) "" ctx
|> renderHtml next ctx |> renderHtml next ctx
| Result.Error e -> return! e next ctx | Result.Error e -> return! e next ctx
} }
/// GET /prayer-requests/email/[date] /// GET /prayer-requests/email/[date]
let email date : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task { let email date : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task {
let startTicks = DateTime.Now.Ticks let startTicks = DateTime.Now.Ticks
@ -93,7 +92,6 @@ let email date : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task {
|> renderHtml next ctx |> renderHtml next ctx
} }
/// POST /prayer-request/[request-id]/delete /// POST /prayer-request/[request-id]/delete
let delete reqId : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun next ctx -> task { let delete reqId : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun next ctx -> task {
let requestId = PrayerRequestId reqId let requestId = PrayerRequestId reqId
@ -107,7 +105,6 @@ let delete reqId : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun
| Result.Error e -> return! e next ctx | Result.Error e -> return! e next ctx
} }
/// GET /prayer-request/[request-id]/expire /// GET /prayer-request/[request-id]/expire
let expire reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task { let expire reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task {
let requestId = PrayerRequestId reqId let requestId = PrayerRequestId reqId
@ -121,7 +118,6 @@ let expire reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task
| Result.Error e -> return! e next ctx | Result.Error e -> return! e next ctx
} }
/// GET /prayer-requests/[group-id]/list /// GET /prayer-requests/[group-id]/list
let list groupId : HttpHandler = requireAccess [ AccessLevel.Public ] >=> fun next ctx -> task { let list groupId : HttpHandler = requireAccess [ AccessLevel.Public ] >=> fun next ctx -> task {
let startTicks = DateTime.Now.Ticks let startTicks = DateTime.Now.Ticks
@ -132,12 +128,12 @@ let list groupId : HttpHandler = requireAccess [ AccessLevel.Public ] >=> fun ne
return! return!
viewInfo ctx startTicks viewInfo ctx startTicks
|> Views.PrayerRequest.list |> Views.PrayerRequest.list
{ Requests = reqs { Requests = reqs
Date = grp.localDateNow clock Date = grp.LocalDateNow clock
SmallGroup = grp SmallGroup = grp
ShowHeader = true ShowHeader = true
CanEmail = Option.isSome ctx.Session.user CanEmail = Option.isSome ctx.Session.user
Recipients = [] Recipients = []
} }
|> renderHtml next ctx |> renderHtml next ctx
| Some _ -> | Some _ ->
@ -147,7 +143,6 @@ let list groupId : HttpHandler = requireAccess [ AccessLevel.Public ] >=> fun ne
| None -> return! fourOhFour next ctx | None -> return! fourOhFour next ctx
} }
/// GET /prayer-requests/lists /// GET /prayer-requests/lists
let lists : HttpHandler = requireAccess [ AccessLevel.Public ] >=> fun next ctx -> task { let lists : HttpHandler = requireAccess [ AccessLevel.Public ] >=> fun next ctx -> task {
let startTicks = DateTime.Now.Ticks let startTicks = DateTime.Now.Ticks
@ -158,7 +153,6 @@ let lists : HttpHandler = requireAccess [ AccessLevel.Public ] >=> fun next ctx
|> renderHtml next ctx |> renderHtml next ctx
} }
/// GET /prayer-requests[/inactive?] /// GET /prayer-requests[/inactive?]
/// - OR - /// - OR -
/// GET /prayer-requests?search=[search-query] /// GET /prayer-requests?search=[search-query]
@ -202,8 +196,6 @@ let print date : HttpHandler = requireAccess [ User; Group ] >=> fun next ctx ->
|> renderHtml next ctx |> renderHtml next ctx
} }
/// GET /prayer-request/[request-id]/restore /// GET /prayer-request/[request-id]/restore
let restore reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task { let restore reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> task {
let requestId = PrayerRequestId reqId let requestId = PrayerRequestId reqId
@ -217,6 +209,7 @@ let restore reqId : HttpHandler = requireAccess [ User ] >=> fun next ctx -> tas
| Result.Error e -> return! e next ctx | Result.Error e -> return! e next ctx
} }
open System.Threading.Tasks
/// POST /prayer-request/save /// POST /prayer-request/save
let save : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun next ctx -> task { let save : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun next ctx -> task {
@ -235,7 +228,7 @@ let save : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun next ct
Expiration = Expiration.fromCode m.Expiration Expiration = Expiration.fromCode m.Expiration
} }
let grp = currentGroup ctx let grp = currentGroup ctx
let now = grp.localDateNow (ctx.GetService<IClock> ()) let now = grp.LocalDateNow (ctx.GetService<IClock> ())
match m.IsNew with match m.IsNew with
| true -> | true ->
let dt = defaultArg m.EnteredDate now let dt = defaultArg m.EnteredDate now
@ -257,7 +250,6 @@ let save : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> fun next ct
| Result.Error e -> return! bindError e next ctx | Result.Error e -> return! bindError e next ctx
} }
/// GET /prayer-request/view/[date?] /// GET /prayer-request/view/[date?]
let view date : HttpHandler = requireAccess [ User; Group ] >=> fun next ctx -> task { let view date : HttpHandler = requireAccess [ User; Group ] >=> fun next ctx -> task {
let startTicks = DateTime.Now.Ticks let startTicks = DateTime.Now.Ticks

View File

@ -16,7 +16,7 @@ let private setGroupCookie (ctx : HttpContext) pwHash =
/// GET /small-group/announcement /// GET /small-group/announcement
let announcement : HttpHandler = requireAccess [ User ] >=> fun next ctx -> let announcement : HttpHandler = requireAccess [ User ] >=> fun next ctx ->
{ viewInfo ctx DateTime.Now.Ticks with HelpLink = Some Help.sendAnnouncement; Script = [ "ckeditor/ckeditor" ] } { viewInfo ctx DateTime.Now.Ticks with HelpLink = Some Help.sendAnnouncement }
|> Views.SmallGroup.announcement (currentUser ctx).IsAdmin ctx |> Views.SmallGroup.announcement (currentUser ctx).IsAdmin ctx
|> renderHtml next ctx |> renderHtml next ctx
@ -266,7 +266,7 @@ let sendAnnouncement : HttpHandler = requireAccess [ User ] >=> validateCsrf >=>
| Ok m -> | Ok m ->
let grp = currentGroup ctx let grp = currentGroup ctx
let usr = currentUser ctx let usr = currentUser ctx
let now = grp.localTimeNow (ctx.GetService<IClock> ()) let now = grp.LocalTimeNow (ctx.GetService<IClock> ())
let s = Views.I18N.localizer.Force () let s = Views.I18N.localizer.Force ()
// Reformat the text to use the class's font stylings // Reformat the text to use the class's font stylings
let requestText = ckEditorToText m.Text let requestText = ckEditorToText m.Text

View File

@ -85,7 +85,7 @@ let delete usrId : HttpHandler = requireAccess [ Admin ] >=> validateCsrf >=> fu
ctx.db.RemoveEntry user ctx.db.RemoveEntry user
let! _ = ctx.db.SaveChangesAsync () let! _ = ctx.db.SaveChangesAsync ()
let s = Views.I18N.localizer.Force () let s = Views.I18N.localizer.Force ()
addInfo ctx s["Successfully deleted user {0}", user.fullName] addInfo ctx s["Successfully deleted user {0}", user.Name]
return! redirectTo false "/users" next ctx return! redirectTo false "/users" next ctx
| _ -> return! fourOhFour next ctx | _ -> return! fourOhFour next ctx
} }
@ -220,10 +220,9 @@ let save : HttpHandler = requireAccess [ Admin ] >=> validateCsrf >=> fun next c
if m.IsNew then if m.IsNew then
let h = CommonFunctions.htmlString let h = CommonFunctions.htmlString
{ UserMessage.info with { UserMessage.info with
Text = h s["Successfully {0} user", s["Added"].Value.ToLower ()] Text = h s["Successfully {0} user", s["Added"].Value.ToLower ()]
Description = Description =
h s["Please select at least one group for which this user ({0}) is authorized", h s["Please select at least one group for which this user ({0}) is authorized", updatedUser.Name]
updatedUser.fullName]
|> Some |> Some
} }
|> addUserMessage ctx |> addUserMessage ctx

View File

@ -1,10 +1,18 @@
/** /**
* This is the main stylesheet for the PrayerTracker application. * This is the main stylesheet for the PrayerTracker application.
*/ */
:root {
--dark-blue-hue: 240;
--dark-blue-sat: 100%;
--darkest: hsl(var(--dark-blue-hue), var(--dark-blue-sat), 6%);
--dark: hsl(var(--dark-blue-hue), var(--dark-blue-sat), 13%);
--lighter-dark: hsl(var(--dark-blue-hue), var(--dark-blue-sat), 25%);
--inverse-backgroud: hsl(0, 0%, 95%);
--background: hsla(0, 0%, 0%, .01);
}
body { body {
background-color: #222; background-color: var(--background);
margin: 0; margin: 0;
margin-bottom: 25px;
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
font-size: 1rem; font-size: 1rem;
} }
@ -18,10 +26,10 @@ a,
a:link, a:link,
a:visited { a:visited {
text-decoration: none; text-decoration: none;
color: navy; color: var(--dark);
} }
a:hover { a:hover {
border-bottom: dotted 1px navy; border-bottom: dotted 1px var(--darkest);
} }
a > img { a > img {
border: 0; border: 0;
@ -32,7 +40,7 @@ a > img {
justify-content: space-between; justify-content: space-between;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
background-image: linear-gradient(to bottom, #222, #444); background-image: linear-gradient(to bottom, var(--darkest), var(--dark));
margin-bottom: 0; margin-bottom: 0;
} }
.pt-title-bar-left, .pt-title-bar-left,
@ -46,7 +54,7 @@ a > img {
float: left; float: left;
font-size: 1.25rem; font-size: 1.25rem;
font-weight: bold; font-weight: bold;
padding: .5rem 1rem 0 1rem; padding: .5rem 1rem 0 .75rem;
} }
.pt-title-bar-home a:link, .pt-title-bar-home a:link,
.pt-title-bar-home a:visited { .pt-title-bar-home a:visited {
@ -87,7 +95,7 @@ a > img {
.pt-title-bar .dropdown-content { .pt-title-bar .dropdown-content {
display: none; display: none;
position: absolute; position: absolute;
background-image: linear-gradient(to bottom, #444, #888); background-image: linear-gradient(to bottom, var(--dark), var(--lighter-dark));
min-width: 160px; min-width: 160px;
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
z-index: 1; z-index: 1;
@ -100,14 +108,14 @@ a > img {
text-align: left; text-align: left;
} }
.pt-title-bar .dropdown-content a:hover { .pt-title-bar .dropdown-content a:hover {
background-color: #222; background-color: var(--inverse-backgroud);
color: var(--lighter-dark);
} }
.pt-title-bar .dropdown:hover .dropdown-content { .pt-title-bar .dropdown:hover .dropdown-content {
display: block; display: block;
} }
#pt-body { #pt-body {
background-color: #fcfcfc; padding-bottom: 1rem;
padding-bottom: 10px;
} }
#pt-language { #pt-language {
background-color: lightgray; background-color: lightgray;
@ -116,31 +124,31 @@ a > img {
justify-content: space-between; justify-content: space-between;
border-bottom: solid 1px darkgray; border-bottom: solid 1px darkgray;
border-top: solid 1px darkgray; border-top: solid 1px darkgray;
padding: 0 .75rem;
} }
#pt-page-title { #pt-page-title {
text-align: center; text-align: center;
border-bottom: dotted 1px lightgray; border-bottom: dotted 1px lightgray;
} }
.pt-content { .pt-content {
margin: auto; margin: auto auto 1.5rem auto;
max-width: 60rem; max-width: 60rem;
} }
.pt-content.pt-full-width { .pt-content.pt-full-width {
max-width: unset; max-width: unset;
margin-left: .5%; margin-left: .75rem;
margin-right: .5%; margin-right: .75rem;
} }
@media screen and (max-width: 60rem) { @media screen and (max-width: 60rem) {
.pt-content { .pt-content {
margin-left: .5%; margin-left: .75rem;
margin-right: .5%; margin-right: .75rem;
} }
} }
fieldset { fieldset {
margin: auto; margin: auto auto 1rem auto;
border: solid 1px #ccc; border: solid 1px #ccc;
border-radius: 1rem; border-radius: 1rem;
margin-bottom: 1rem;
} }
input[type=email], input[type=email],
input[type=text], input[type=text],
@ -148,7 +156,8 @@ input[type=password],
input[type=date], input[type=date],
input[type=number], input[type=number],
select { select {
border-radius: 5px; border-radius: .25rem;
border-color: var(--lighter-dark);
font-size: 1rem; font-size: 1rem;
padding: .2rem; padding: .2rem;
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
@ -160,30 +169,40 @@ button[type=submit] {
border-radius: 10px; border-radius: 10px;
padding: .2rem 1rem; padding: .2rem 1rem;
margin-top: .5rem; margin-top: .5rem;
background-color: #444; background-color: var(--lighter-dark);
border: none; border: solid 1px var(--lighter-dark);
color: white; color: white;
} }
button[type=submit]:hover { button[type=submit]:hover {
background-color: #222; color: var(--lighter-dark);
cursor:pointer; background-color: var(--inverse-backgroud);
cursor: pointer;
} }
footer { footer.pt-footer {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
width: 100%; width: 100%;
border-bottom: solid 10px #222; padding-top: .5rem;
background-image: linear-gradient(to bottom, var(--background), var(--darkest));
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-items: end;
} }
#pt-legal { #pt-legal {
background-color: #222; padding-left: .75rem;
margin: 0 0 -30px 0;
padding-left: 10px;
} }
#pt-legal a:link, #pt-legal a:link,
#pt-legal a:visited { #pt-legal a:visited {
color: lightgray; color: white;
color: rgba(255, 255, 255, .5);
font-size: 10pt; font-size: 10pt;
background-color: var(--darkest);
padding: 0 .5rem;
border-top-left-radius: .5rem;
border-top-right-radius: .5rem;
}
#pt-legal a:hover {
background-color: var(--lighter-dark);
} }
#pt-footer { #pt-footer {
border: solid 2px navy; border: solid 2px navy;
@ -191,12 +210,10 @@ footer {
border-top-left-radius: 7px; border-top-left-radius: 7px;
border-top-right-radius: 7px; border-top-right-radius: 7px;
padding: 2px 5px 0 5px; padding: 2px 5px 0 5px;
margin: 0 10px -11px auto; margin-right: .75rem;
font-size: 70%; font-size: 70%;
color: navy; color: navy;
background-color: #eee; background-color: #eee;
float:right;
vertical-align: bottom;
} }
#pt-footer img { #pt-footer img {
vertical-align: bottom; vertical-align: bottom;
@ -300,7 +317,7 @@ article.pt-overview section header {
text-align: center; text-align: center;
border-top-left-radius: 1rem; border-top-left-radius: 1rem;
border-top-right-radius: 1rem; border-top-right-radius: 1rem;
background-image: linear-gradient(to bottom, #444, #888); background-image: linear-gradient(to bottom, var(--dark), var(--lighter-dark));
padding: .5rem 1rem; padding: .5rem 1rem;
color: white; color: white;
} }
@ -308,7 +325,7 @@ article.pt-overview section div {
padding: .5rem; padding: .5rem;
} }
article.pt-overview section div hr { article.pt-overview section div hr {
color: #444; color: var(--dark);
margin: .5rem -.5rem; margin: .5rem -.5rem;
} }
article.pt-overview section div p { article.pt-overview section div p {

106
src/names-to-lower.sql Normal file
View File

@ -0,0 +1,106 @@
-- Church
ALTER TABLE pt."Church" RENAME COLUMN "ChurchId" TO id;
ALTER TABLE pt."Church" RENAME COLUMN "Name" TO church_name;
ALTER TABLE pt."Church" RENAME COLUMN "City" TO city;
ALTER TABLE pt."Church" RENAME COLUMN "ST" TO state;
ALTER TABLE pt."Church" RENAME COLUMN "HasVirtualPrayerRoomInterface" TO has_vps_interface;
ALTER TABLE pt."Church" RENAME COLUMN "InterfaceAddress" TO interface_address;
ALTER TABLE pt."Church" RENAME CONSTRAINT "PK_Church" TO pk_church;
ALTER TABLE pt."Church" RENAME TO church;
-- List Preference
ALTER TABLE pt."ListPreference" RENAME COLUMN "SmallGroupId" TO small_group_id;
ALTER TABLE pt."ListPreference" RENAME COLUMN "DaysToExpire" TO days_to_expire;
ALTER TABLE pt."ListPreference" RENAME COLUMN "DaysToKeepNew" TO days_to_keep_new;
ALTER TABLE pt."ListPreference" RENAME COLUMN "LongTermUpdateWeeks" TO long_term_update_weeks;
ALTER TABLE pt."ListPreference" RENAME COLUMN "EmailFromName" TO email_from_name;
ALTER TABLE pt."ListPreference" RENAME COLUMN "EmailFromAddress" TO email_from_address;
ALTER TABLE pt."ListPreference" RENAME COLUMN "ListFonts" TO fonts;
ALTER TABLE pt."ListPreference" RENAME COLUMN "HeadingColor" TO heading_color;
ALTER TABLE pt."ListPreference" RENAME COLUMN "LineColor" TO line_color;
ALTER TABLE pt."ListPreference" RENAME COLUMN "HeadingFontSize" TO heading_font_size;
ALTER TABLE pt."ListPreference" RENAME COLUMN "TextFontSize" TO text_font_size;
ALTER TABLE pt."ListPreference" RENAME COLUMN "RequestSort" TO request_sort;
ALTER TABLE pt."ListPreference" RENAME COLUMN "GroupPassword" TO group_password;
ALTER TABLE pt."ListPreference" RENAME COLUMN "DefaultEmailType" TO default_email_type;
ALTER TABLE pt."ListPreference" RENAME COLUMN "IsPublic" TO is_public;
ALTER TABLE pt."ListPreference" RENAME COLUMN "TimeZoneId" TO time_zone_id;
ALTER TABLE pt."ListPreference" RENAME COLUMN "PageSize" TO page_size;
ALTER TABLE pt."ListPreference" RENAME COLUMN "AsOfDateDisplay" TO as_of_date_display;
ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "PK_ListPreference" TO pk_list_preference;
ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "FK_ListPreference_SmallGroup_SmallGroupId" TO fk_list_preference_small_group_id;
ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "FK_ListPreference_TimeZone_TimeZoneId" TO fk_list_preference_time_zone_id;
ALTER TABLE pt."ListPreference" RENAME TO list_preference;
ALTER INDEX pt."IX_ListPreference_TimeZoneId" RENAME TO ix_list_preference_time_zone_id;
-- Small Group Member
ALTER TABLE pt."Member" RENAME COLUMN "MemberId" TO id;
ALTER TABLE pt."Member" RENAME COLUMN "SmallGroupId" TO small_group_id;
ALTER TABLE pt."Member" RENAME COLUMN "MemberName" TO member_name;
ALTER TABLE pt."Member" RENAME COLUMN "Email" TO email;
ALTER TABLE pt."Member" RENAME COLUMN "Format" TO email_format;
ALTER TABLE pt."Member" RENAME CONSTRAINT "PK_Member" TO pk_member;
ALTER TABLE pt."Member" RENAME CONSTRAINT "FK_Member_SmallGroup_SmallGroupId" TO fk_member_small_group_id;
ALTER TABLE pt."Member" RENAME TO member;
ALTER INDEX pt."IX_Member_SmallGroupId" RENAME TO ix_member_small_group_id;
-- Prayer Request
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "PrayerRequestId" TO id;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "RequestType" TO request_type;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "UserId" TO user_id;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "SmallGroupId" TO small_group_id;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "EnteredDate" TO entered_date;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "UpdatedDate" TO updated_date;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "Requestor" TO requestor;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "Text" TO request_text;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "NotifyChaplain" TO notify_chaplain;
ALTER TABLE pt."PrayerRequest" RENAME COLUMN "Expiration" TO expiration;
ALTER TABLE pt."PrayerRequest" RENAME CONSTRAINT "PK_PrayerRequest" TO pk_prayer_request;
ALTER TABLE pt."PrayerRequest" RENAME CONSTRAINT "FK_PrayerRequest_User_UserId" TO fk_prayer_request_user_id;
ALTER TABLE pt."PrayerRequest" RENAME CONSTRAINT "FK_PrayerRequest_SmallGroup_SmallGroupId" TO fk_prayer_request_small_group_id;
ALTER TABLE pt."PrayerRequest" RENAME TO prayer_request;
ALTER INDEX pt."IX_PrayerRequest_UserId" RENAME TO ix_prayer_request_user_id;
ALTER INDEX pt."IX_PrayerRequest_SmallGroupId" RENAME TO ix_prayer_request_small_group_id;
ALTER INDEX pt."IX_PrayerRequest_Requestor_TRGM" RENAME TO ix_prayer_request_trgm_requestor;
ALTER INDEX pt."IX_PrayerRequest_Text_TRGM" RENAME TO ix_prayer_request_trgm_request_text;
-- Small Group
ALTER TABLE pt."SmallGroup" RENAME COLUMN "SmallGroupId" TO id;
ALTER TABLE pt."SmallGroup" RENAME COLUMN "ChurchId" TO church_id;
ALTER TABLE pt."SmallGroup" RENAME COLUMN "Name" TO group_name;
ALTER TABLE pt."SmallGroup" RENAME CONSTRAINT "PK_SmallGroup" TO pk_small_group;
ALTER TABLE pt."SmallGroup" RENAME CONSTRAINT "FK_SmallGroup_Church_ChurchId" TO fk_small_group_church_id;
ALTER TABLE pt."SmallGroup" RENAME TO small_group;
ALTER INDEX pt."IX_SmallGroup_ChurchId" RENAME TO ix_small_group_church_id;
-- Time Zone
ALTER TABLE pt."TimeZone" RENAME COLUMN "TimeZoneId" TO id;
ALTER TABLE pt."TimeZone" RENAME COLUMN "Description" TO description;
ALTER TABLE pt."TimeZone" RENAME COLUMN "SortOrder" TO sort_order;
ALTER TABLE pt."TimeZone" RENAME COLUMN "IsActive" TO is_active;
ALTER TABLE pt."TimeZone" RENAME CONSTRAINT "PK_TimeZone" TO pk_time_zone;
ALTER TABLE pt."TimeZone" RENAME TO time_zone;
-- User
ALTER TABLE pt."User" RENAME COLUMN "UserId" TO id;
ALTER TABLE pt."User" RENAME COLUMN "FirstName" TO first_name;
ALTER TABLE pt."User" RENAME COLUMN "LastName" TO last_name;
ALTER TABLE pt."User" RENAME COLUMN "EmailAddress" TO email;
ALTER TABLE pt."User" RENAME COLUMN "IsSystemAdmin" TO is_admin;
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;
-- User / Small Group
ALTER TABLE pt."User_SmallGroup" RENAME COLUMN "UserId" TO user_id;
ALTER TABLE pt."User_SmallGroup" RENAME COLUMN "SmallGroupId" TO small_group_id;
ALTER TABLE pt."User_SmallGroup" RENAME CONSTRAINT "PK_User_SmallGroup" TO pk_user_small_group;
ALTER TABLE pt."User_SmallGroup" RENAME CONSTRAINT "FK_User_SmallGroup_User_UserId" TO fk_user_small_group_user_id;
ALTER TABLE pt."User_SmallGroup" RENAME CONSTRAINT "FK_User_SmallGroup_SmallGroup_SmallGroupId" TO fk_user_small_group_small_group_id;
ALTER TABLE pt."User_SmallGroup" RENAME TO user_small_group;
ALTER INDEX pt."IX_User_SmallGroup_SmallGroupId" RENAME TO ix_user_small_group_small_group_id;