- Removed fixi library (not a good fit)
This commit is contained in:
parent
2e5a1426f6
commit
c9ccfe8b68
@ -68,6 +68,10 @@ module Json =
|
|||||||
opts
|
opts
|
||||||
|
|
||||||
|
|
||||||
|
module private Helpers =
|
||||||
|
let instant (it: Instant) =
|
||||||
|
it.ToString()
|
||||||
|
|
||||||
open BitBadger.Documents
|
open BitBadger.Documents
|
||||||
open BitBadger.Documents.Sqlite
|
open BitBadger.Documents.Sqlite
|
||||||
|
|
||||||
@ -120,19 +124,19 @@ module SmallGroups =
|
|||||||
|
|
||||||
/// Query to retrieve data for a small group info instance
|
/// Query to retrieve data for a small group info instance
|
||||||
let private infoQuery =
|
let private infoQuery =
|
||||||
$"SELECT g.data->>'id' AS id, g.data->>'groupName' AS groupName, c.data->>'churchName' AS churchName,
|
$"SELECT g.data->>'id' AS id, g.data->>'name' AS groupName, c.data->>'name' AS churchName,
|
||||||
g.data->'preferences'->>'timeZoneId' AS timeZoneId, g.data->'preferences'->>'isPublic' AS isPublic
|
g.data->'preferences'->>'timeZoneId' AS timeZoneId, g.data->'preferences'->>'isPublic' AS isPublic
|
||||||
FROM {Table.Group} g
|
FROM {Table.Group} g
|
||||||
INNER JOIN {Table.Church} c ON c.data->>'id' = g.data->>'churchId'"
|
INNER JOIN {Table.Church} c ON c.data->>'id' = g.data->>'churchId'"
|
||||||
|
|
||||||
/// Query to retrieve data for a small group select list item
|
/// Query to retrieve data for a small group select list item
|
||||||
let private itemQuery =
|
let private itemQuery =
|
||||||
$"SELECT g.data->>'groupName' AS groupName, g.data->>'id' AS id, c.data->>'churchName' AS churchName
|
$"SELECT g.data->>'name' AS groupName, g.data->>'id' AS id, c.data->>'name' AS churchName
|
||||||
FROM {Table.Group} g
|
FROM {Table.Group} g
|
||||||
INNER JOIN {Table.Church} c ON c.data->>'id' = g.data->>'churchId'"
|
INNER JOIN {Table.Church} c ON c.data->>'id' = g.data->>'churchId'"
|
||||||
|
|
||||||
/// The ORDER BY clause for select list item queries
|
/// The ORDER BY clause for select list item queries
|
||||||
let private itemOrderBy = "ORDER BY c.data->>'churchName', g.data->>'groupName'"
|
let private itemOrderBy = "ORDER BY c.data->>'name', g.data->>'name'"
|
||||||
|
|
||||||
/// Map a row to a Small Group list item
|
/// Map a row to a Small Group list item
|
||||||
let private toSmallGroupItem (rdr: SqliteDataReader) =
|
let private toSmallGroupItem (rdr: SqliteDataReader) =
|
||||||
@ -142,13 +146,13 @@ module SmallGroups =
|
|||||||
/// Get the group IDs for the given church
|
/// Get the group IDs for the given church
|
||||||
let internal groupIdsByChurch (churchId: ChurchId) =
|
let internal groupIdsByChurch (churchId: ChurchId) =
|
||||||
backgroundTask {
|
backgroundTask {
|
||||||
let! groups = Find.byFields<SmallGroup> Table.Group All [ Field.Equal "churchId" churchId ]
|
let! groups = Find.byFields<SmallGroup> Table.Group All [ Field.Equal "churchId" (string churchId) ]
|
||||||
return groups |> List.map _.Id
|
return groups |> List.map _.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Count the number of small groups for a church
|
/// Count the number of small groups for a church
|
||||||
let countByChurch (churchId: ChurchId) =
|
let countByChurch (churchId: ChurchId) =
|
||||||
Count.byFields Table.Group All [ Field.Equal "churchId" churchId ]
|
Count.byFields Table.Group All [ Field.Equal "churchId" (string churchId) ]
|
||||||
|
|
||||||
/// Delete a small group by its ID
|
/// Delete a small group by its ID
|
||||||
let deleteById (groupId: SmallGroupId) =
|
let deleteById (groupId: SmallGroupId) =
|
||||||
@ -156,20 +160,21 @@ module SmallGroups =
|
|||||||
use conn = Configuration.dbConn ()
|
use conn = Configuration.dbConn ()
|
||||||
use! txn = conn.BeginTransactionAsync()
|
use! txn = conn.BeginTransactionAsync()
|
||||||
|
|
||||||
let! users = Find.byFields<User> Table.User All [ Field.InArray "smallGroups" Table.User [ groupId ] ]
|
let! users =
|
||||||
|
Find.byFields<User> Table.User All [ Field.InArray "smallGroups" Table.User [ (string groupId) ] ]
|
||||||
|
|
||||||
for user in users do
|
for user in users do
|
||||||
do! Patch.byId Table.User user.Id {| SmallGroups = user.SmallGroups |> List.except [ groupId ] |}
|
do! Patch.byId Table.User user.Id {| SmallGroups = user.SmallGroups |> List.except [ groupId ] |}
|
||||||
|
|
||||||
do! conn.deleteByFields Table.Request All [ Field.Equal "smallGroupId" groupId ]
|
do! conn.deleteByFields Table.Request All [ Field.Equal "smallGroupId" (string groupId) ]
|
||||||
do! conn.deleteById Table.Group groupId
|
do! conn.deleteById Table.Group (string groupId)
|
||||||
|
|
||||||
do! txn.CommitAsync()
|
do! txn.CommitAsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get information for all small groups
|
/// Get information for all small groups
|
||||||
let infoForAll () =
|
let infoForAll () =
|
||||||
Custom.list $"{infoQuery} ORDER BY g.data->>'groupName'" [] SmallGroupInfo.FromReader
|
Custom.list $"{infoQuery} ORDER BY g.data->>'name'" [] SmallGroupInfo.FromReader
|
||||||
|
|
||||||
/// Get a list of small group IDs along with a description that includes the church name
|
/// Get a list of small group IDs along with a description that includes the church name
|
||||||
let listAll () =
|
let listAll () =
|
||||||
@ -197,14 +202,14 @@ module SmallGroups =
|
|||||||
Find.firstByFields<SmallGroup>
|
Find.firstByFields<SmallGroup>
|
||||||
Table.Group
|
Table.Group
|
||||||
All
|
All
|
||||||
[ Field.Equal "id" groupId; Field.Equal "preferences.groupPassword" password ]
|
[ Field.Equal "id" (string groupId); Field.Equal "preferences.groupPassword" password ]
|
||||||
|
|
||||||
/// Save a small group
|
/// Save a small group
|
||||||
let save group = save<SmallGroup> Table.Group group
|
let save group = save<SmallGroup> Table.Group group
|
||||||
|
|
||||||
/// Save a small group's list preferences
|
/// Save a small group's list preferences
|
||||||
let savePreferences (groupId: SmallGroupId) (pref: ListPreferences) =
|
let savePreferences (groupId: SmallGroupId) (pref: ListPreferences) =
|
||||||
Patch.byId Table.Group groupId {| Preferences = pref |}
|
Patch.byId Table.Group (string groupId) {| Preferences = pref |}
|
||||||
|
|
||||||
/// Get a small group by its ID (including list preferences)
|
/// Get a small group by its ID (including list preferences)
|
||||||
let tryById groupId =
|
let tryById groupId =
|
||||||
@ -223,17 +228,18 @@ module Churches =
|
|||||||
use conn = Configuration.dbConn ()
|
use conn = Configuration.dbConn ()
|
||||||
use! txn = conn.BeginTransactionAsync()
|
use! txn = conn.BeginTransactionAsync()
|
||||||
|
|
||||||
let! groupIds = SmallGroups.groupIdsByChurch churchId
|
let! groupIds = SmallGroups.groupIdsByChurch churchId
|
||||||
|
let gIdStrings = groupIds |> List.map string
|
||||||
|
|
||||||
do! Delete.byFields Table.Request All [ Field.In "smallGroupId" groupIds ]
|
do! Delete.byFields Table.Request All [ Field.In "smallGroupId" gIdStrings ]
|
||||||
|
|
||||||
let! users = Find.byFields<User> Table.User All [ Field.InArray "smallGroups" Table.User groupIds ]
|
let! users = Find.byFields<User> Table.User All [ Field.InArray "smallGroups" Table.User gIdStrings ]
|
||||||
|
|
||||||
for user in users do
|
for user in users do
|
||||||
do! Patch.byId Table.User user.Id {| SmallGroups = user.SmallGroups |> List.except groupIds |}
|
do! Patch.byId Table.User (string user.Id) {| SmallGroups = user.SmallGroups |> List.except groupIds |}
|
||||||
|
|
||||||
do! Delete.byFields Table.Group All [ Field.Equal "churchId" churchId ]
|
do! Delete.byFields Table.Group All [ Field.Equal "churchId" (string churchId) ]
|
||||||
do! Delete.byId Table.Church churchId
|
do! Delete.byId Table.Church (string churchId)
|
||||||
do! txn.CommitAsync()
|
do! txn.CommitAsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,17 +256,17 @@ module Members =
|
|||||||
|
|
||||||
/// Count members for the given small group
|
/// Count members for the given small group
|
||||||
let countByGroup (groupId: SmallGroupId) =
|
let countByGroup (groupId: SmallGroupId) =
|
||||||
Count.byFields Table.Member All [ Field.Equal "smallGroupId" groupId ]
|
Count.byFields Table.Member All [ Field.Equal "smallGroupId" (string groupId) ]
|
||||||
|
|
||||||
/// Delete a small group member by its ID
|
/// Delete a small group member by its ID
|
||||||
let deleteById (memberId: MemberId) = Delete.byId Table.Member memberId
|
let deleteById (memberId: MemberId) = Delete.byId Table.Member (string memberId)
|
||||||
|
|
||||||
/// Retrieve all members for a given small group
|
/// Retrieve all members for a given small group
|
||||||
let forGroup (groupId: SmallGroupId) =
|
let forGroup (groupId: SmallGroupId) =
|
||||||
Find.byFieldsOrdered<Member>
|
Find.byFieldsOrdered<Member>
|
||||||
Table.Member
|
Table.Member
|
||||||
All
|
All
|
||||||
[ Field.Equal "smallGroupId" groupId ]
|
[ Field.Equal "smallGroupId" (string groupId) ]
|
||||||
[ Field.Named "memberName" ]
|
[ Field.Named "memberName" ]
|
||||||
|
|
||||||
/// Save a small group member
|
/// Save a small group member
|
||||||
@ -312,15 +318,15 @@ module PrayerRequests =
|
|||||||
let countByChurch churchId =
|
let countByChurch churchId =
|
||||||
backgroundTask {
|
backgroundTask {
|
||||||
let! groupIds = SmallGroups.groupIdsByChurch churchId
|
let! groupIds = SmallGroups.groupIdsByChurch churchId
|
||||||
return! Count.byFields Table.Request All [ Field.In "smallGroupId" groupIds ]
|
return! Count.byFields Table.Request All [ Field.In "smallGroupId" (List.map string groupIds) ]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Count the number of prayer requests for a small group
|
/// Count the number of prayer requests for a small group
|
||||||
let countByGroup (groupId: SmallGroupId) =
|
let countByGroup (groupId: SmallGroupId) =
|
||||||
Count.byFields Table.Request All [ Field.Equal "smallGroupId" groupId ]
|
Count.byFields Table.Request All [ Field.Equal "smallGroupId" (string groupId) ]
|
||||||
|
|
||||||
/// Delete a prayer request by its ID
|
/// Delete a prayer request by its ID
|
||||||
let deleteById (reqId: PrayerRequestId) = Delete.byId Table.Request reqId
|
let deleteById (reqId: PrayerRequestId) = Delete.byId Table.Request (string reqId)
|
||||||
|
|
||||||
/// 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
|
||||||
let forGroup (opts: PrayerRequestOptions) =
|
let forGroup (opts: PrayerRequestOptions) =
|
||||||
@ -332,11 +338,11 @@ module PrayerRequests =
|
|||||||
(theDate.AtStartOfDayInZone(opts.SmallGroup.TimeZone)
|
(theDate.AtStartOfDayInZone(opts.SmallGroup.TimeZone)
|
||||||
- Duration.FromDays opts.SmallGroup.Preferences.DaysToExpire)
|
- Duration.FromDays opts.SmallGroup.Preferences.DaysToExpire)
|
||||||
.ToInstant()
|
.ToInstant()
|
||||||
$"""AND ( data->>'updatedDate' > :updatedDate
|
$"""AND ( date(data->>'updatedDate') > date(:updatedDate)
|
||||||
OR data->>'expiration' = :expManual
|
OR data->>'expiration' = :expManual
|
||||||
OR data->>'requestType' IN (:typLongTerm, :typExpecting))
|
OR data->>'requestType' IN (:typLongTerm, :typExpecting))
|
||||||
AND data->>'expiration' <> :expForced""",
|
AND data->>'expiration' <> :expForced""",
|
||||||
[ SqliteParameter(":updatedDate", expDate)
|
[ SqliteParameter(":updatedDate", string expDate)
|
||||||
SqliteParameter(":expManual", string Manual)
|
SqliteParameter(":expManual", string Manual)
|
||||||
SqliteParameter(":typLongTerm", string LongTermRequest)
|
SqliteParameter(":typLongTerm", string LongTermRequest)
|
||||||
SqliteParameter(":typExpecting", string Expecting)
|
SqliteParameter(":typExpecting", string Expecting)
|
||||||
@ -346,8 +352,9 @@ module PrayerRequests =
|
|||||||
|
|
||||||
Custom.list
|
Custom.list
|
||||||
$"SELECT data FROM {Table.Request}
|
$"SELECT data FROM {Table.Request}
|
||||||
WHERE data->>'smallGroupId = :groupId {sql}
|
WHERE data->>'smallGroupId' = :groupId
|
||||||
ORDER BY {orderBy opts.SmallGroup.Preferences.RequestSort}
|
{sql}
|
||||||
|
{orderBy opts.SmallGroup.Preferences.RequestSort}
|
||||||
{paginate opts.PageNumber opts.SmallGroup.Preferences.PageSize}"
|
{paginate opts.PageNumber opts.SmallGroup.Preferences.PageSize}"
|
||||||
(SqliteParameter(":groupId", string opts.SmallGroup.Id) :: parameters)
|
(SqliteParameter(":groupId", string opts.SmallGroup.Id) :: parameters)
|
||||||
fromData<PrayerRequest>
|
fromData<PrayerRequest>
|
||||||
@ -357,18 +364,20 @@ module PrayerRequests =
|
|||||||
|
|
||||||
/// Search prayer requests for the given term
|
/// Search prayer requests for the given term
|
||||||
let searchForGroup group searchTerm pageNbr =
|
let searchForGroup group searchTerm pageNbr =
|
||||||
|
let pct = "%"
|
||||||
Custom.list
|
Custom.list
|
||||||
$"SELECT data FROM {Table.Request}
|
$"WITH results AS (
|
||||||
WHERE data->>'smallGroupId' = :groupId
|
SELECT data FROM {Table.Request}
|
||||||
AND data->>'requestText' LIKE :search
|
WHERE data->>'smallGroupId' = :groupId
|
||||||
UNION
|
AND data->>'text' LIKE :search
|
||||||
SELECT data FROM {Table.Request}
|
UNION
|
||||||
WHERE data->>'smallGroupId' = :groupId
|
SELECT data FROM {Table.Request}
|
||||||
AND COALESCE(data->>'requestor', '') LIKE :search
|
WHERE data->>'smallGroupId' = :groupId
|
||||||
ORDER BY {orderBy group.Preferences.RequestSort}
|
AND COALESCE(data->>'requestor', '') LIKE :search)
|
||||||
|
SELECT data FROM results
|
||||||
|
{orderBy group.Preferences.RequestSort}
|
||||||
{paginate pageNbr group.Preferences.PageSize}"
|
{paginate pageNbr group.Preferences.PageSize}"
|
||||||
[ SqliteParameter(":groupId", string group.Id)
|
[ SqliteParameter(":groupId", string group.Id); SqliteParameter(":search", $"{pct}%s{searchTerm}{pct}") ]
|
||||||
SqliteParameter(":search", $"%%%s{searchTerm}%%") ]
|
|
||||||
fromData<PrayerRequest>
|
fromData<PrayerRequest>
|
||||||
|
|
||||||
/// Retrieve a prayer request by its ID
|
/// Retrieve a prayer request by its ID
|
||||||
@ -380,11 +389,11 @@ module PrayerRequests =
|
|||||||
if withTime then
|
if withTime then
|
||||||
Patch.byId
|
Patch.byId
|
||||||
Table.Request
|
Table.Request
|
||||||
req.Id
|
(string req.Id)
|
||||||
{| UpdatedDate = req.UpdatedDate
|
{| UpdatedDate = req.UpdatedDate
|
||||||
Expiration = req.Expiration |}
|
Expiration = req.Expiration |}
|
||||||
else
|
else
|
||||||
Patch.byId Table.Request req.Id {| Expiration = req.Expiration |}
|
Patch.byId Table.Request (string req.Id) {| Expiration = req.Expiration |}
|
||||||
|
|
||||||
|
|
||||||
/// Functions to manipulate users
|
/// Functions to manipulate users
|
||||||
@ -398,22 +407,22 @@ module Users =
|
|||||||
let countByChurch churchId =
|
let countByChurch churchId =
|
||||||
backgroundTask {
|
backgroundTask {
|
||||||
let! groupIds = SmallGroups.groupIdsByChurch churchId
|
let! groupIds = SmallGroups.groupIdsByChurch churchId
|
||||||
return! Count.byFields Table.User All [ Field.InArray "smallGroups" Table.User groupIds ]
|
return! Count.byFields Table.User All [ Field.InArray "smallGroups" Table.User (List.map string groupIds) ]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Count the number of users for a small group
|
/// Count the number of users for a small group
|
||||||
let countByGroup (groupId: SmallGroupId) =
|
let countByGroup (groupId: SmallGroupId) =
|
||||||
Count.byFields Table.User All [ Field.InArray "smallGroups" Table.User [ groupId ] ]
|
Count.byFields Table.User All [ Field.InArray "smallGroups" Table.User [ (string groupId) ] ]
|
||||||
|
|
||||||
/// Delete a user by its database ID
|
/// Delete a user by its database ID
|
||||||
let deleteById (userId: UserId) = Delete.byId Table.User userId
|
let deleteById (userId: UserId) = Delete.byId Table.User (string userId)
|
||||||
|
|
||||||
/// Get a list of users authorized to administer the given small group
|
/// Get a list of users authorized to administer the given small group
|
||||||
let listByGroupId (groupId: SmallGroupId) =
|
let listByGroupId (groupId: SmallGroupId) =
|
||||||
Find.byFieldsOrdered<User>
|
Find.byFieldsOrdered<User>
|
||||||
Table.User
|
Table.User
|
||||||
All
|
All
|
||||||
[ Field.InArray "smallGroups" Table.User [ groupId ] ]
|
[ Field.InArray "smallGroups" Table.User [ (string groupId) ] ]
|
||||||
[ Field.Named "lastName"; Field.Named "firstName" ]
|
[ Field.Named "lastName"; Field.Named "firstName" ]
|
||||||
|
|
||||||
/// Save a user's information
|
/// Save a user's information
|
||||||
@ -425,7 +434,7 @@ module Users =
|
|||||||
Table.User
|
Table.User
|
||||||
All
|
All
|
||||||
[ Field.Equal "email" email
|
[ Field.Equal "email" email
|
||||||
Field.InArray "smallGroups" Table.User [ groupId ] ]
|
Field.InArray "smallGroups" Table.User [ (string groupId) ] ]
|
||||||
|
|
||||||
/// Find a user by their database ID
|
/// Find a user by their database ID
|
||||||
let tryById userId =
|
let tryById userId =
|
||||||
@ -433,12 +442,12 @@ module Users =
|
|||||||
|
|
||||||
/// Update a user's last seen date/time
|
/// Update a user's last seen date/time
|
||||||
let updateLastSeen (userId: UserId) (now: Instant) =
|
let updateLastSeen (userId: UserId) (now: Instant) =
|
||||||
Patch.byId Table.User userId {| LastSeen = now |}
|
Patch.byId Table.User (string userId) {| LastSeen = now |}
|
||||||
|
|
||||||
/// Update a user's password hash
|
/// Update a user's password hash
|
||||||
let updatePassword (user: User) =
|
let updatePassword (user: User) =
|
||||||
Patch.byId Table.User user.Id {| PasswordHash = user.PasswordHash |}
|
Patch.byId Table.User (string user.Id) {| PasswordHash = user.PasswordHash |}
|
||||||
|
|
||||||
/// Update a user's authorized small groups
|
/// Update a user's authorized small groups
|
||||||
let updateSmallGroups (userId: UserId) (groupIds: SmallGroupId list) =
|
let updateSmallGroups (userId: UserId) (groupIds: SmallGroupId list) =
|
||||||
Patch.byId Table.User userId {| SmallGroups = groupIds |}
|
Patch.byId Table.User (string userId) {| SmallGroups = groupIds |}
|
||||||
|
@ -87,6 +87,7 @@ module Configure =
|
|||||||
let cachePath = defaultArg (Option.ofObj (cfg.GetConnectionString "SessionDB")) "./data/session.db"
|
let cachePath = defaultArg (Option.ofObj (cfg.GetConnectionString "SessionDB")) "./data/session.db"
|
||||||
let _ = svc.AddSqliteCache(fun o -> o.CachePath <- cachePath)
|
let _ = svc.AddSqliteCache(fun o -> o.CachePath <- cachePath)
|
||||||
let _ = svc.AddSession()
|
let _ = svc.AddSession()
|
||||||
|
let _ = svc.AddLogging()
|
||||||
let _ = svc.AddAntiforgery()
|
let _ = svc.AddAntiforgery()
|
||||||
let _ = svc.AddRouting()
|
let _ = svc.AddRouting()
|
||||||
let _ = svc.AddSingleton<IClock> SystemClock.Instance
|
let _ = svc.AddSingleton<IClock> SystemClock.Instance
|
||||||
@ -219,8 +220,8 @@ module Configure =
|
|||||||
open Microsoft.Extensions.Options
|
open Microsoft.Extensions.Options
|
||||||
|
|
||||||
/// Configure the application
|
/// Configure the application
|
||||||
let app (app: IApplicationBuilder) =
|
let app (app: WebApplication) =
|
||||||
let env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>()
|
let env = app.Services.GetRequiredService<IWebHostEnvironment>()
|
||||||
|
|
||||||
if env.IsDevelopment() then
|
if env.IsDevelopment() then
|
||||||
app.UseDeveloperExceptionPage()
|
app.UseDeveloperExceptionPage()
|
||||||
@ -232,24 +233,20 @@ module Configure =
|
|||||||
let _ = app.UseCanonicalDomains()
|
let _ = app.UseCanonicalDomains()
|
||||||
let _ = app.UseStatusCodePagesWithReExecute "/error/{0}"
|
let _ = app.UseStatusCodePagesWithReExecute "/error/{0}"
|
||||||
let _ = app.UseStaticFiles()
|
let _ = app.UseStaticFiles()
|
||||||
|
let _ = app.UseCookiePolicy(CookiePolicyOptions(MinimumSameSitePolicy = SameSiteMode.Strict))
|
||||||
let _ =
|
|
||||||
app.UseCookiePolicy(CookiePolicyOptions(MinimumSameSitePolicy = SameSiteMode.Strict))
|
|
||||||
|
|
||||||
let _ = app.UseMiddleware<RequestStartMiddleware>()
|
let _ = app.UseMiddleware<RequestStartMiddleware>()
|
||||||
let _ = app.UseRouting()
|
let _ = app.UseRouting()
|
||||||
let _ = app.UseSession()
|
let _ = app.UseSession()
|
||||||
|
let _ = app.UseRequestLocalization(app.Services.GetService<IOptions<RequestLocalizationOptions>>().Value)
|
||||||
let _ =
|
|
||||||
app.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value)
|
|
||||||
|
|
||||||
let _ = app.UseAuthentication()
|
let _ = app.UseAuthentication()
|
||||||
let _ = app.UseAuthorization()
|
let _ = app.UseAuthorization()
|
||||||
let _ = app.UseEndpoints(fun e -> e.MapGiraffeEndpoints routes)
|
let _ = app.UseEndpoints(fun e -> e.MapGiraffeEndpoints routes)
|
||||||
|
|
||||||
app.ApplicationServices.GetRequiredService<IStringLocalizerFactory>()
|
app.Services.GetRequiredService<IStringLocalizerFactory>()
|
||||||
|> Views.I18N.setUpFactories
|
|> Views.I18N.setUpFactories
|
||||||
|
|
||||||
|
open Microsoft.Extensions.DependencyInjection
|
||||||
|
open Microsoft.Extensions.Logging
|
||||||
|
|
||||||
/// The web application
|
/// The web application
|
||||||
module App =
|
module App =
|
||||||
@ -258,22 +255,32 @@ module App =
|
|||||||
|
|
||||||
[<EntryPoint>]
|
[<EntryPoint>]
|
||||||
let main args =
|
let main args =
|
||||||
let contentRoot = Directory.GetCurrentDirectory()
|
|
||||||
|
|
||||||
let app =
|
let contentRoot = Directory.GetCurrentDirectory()
|
||||||
WebHostBuilder()
|
let builder =
|
||||||
.UseContentRoot(contentRoot)
|
WebApplication.CreateBuilder(
|
||||||
|
WebApplicationOptions(
|
||||||
|
Args = args,
|
||||||
|
ApplicationName = "PrayerTracker",
|
||||||
|
ContentRootPath = contentRoot,
|
||||||
|
WebRootPath = Path.Combine(contentRoot, "wwwroot")))
|
||||||
|
let _ =
|
||||||
|
builder.WebHost
|
||||||
.ConfigureAppConfiguration(Configure.configuration)
|
.ConfigureAppConfiguration(Configure.configuration)
|
||||||
.UseKestrel(Configure.kestrel)
|
.ConfigureKestrel(Configure.kestrel)
|
||||||
.UseWebRoot(Path.Combine(contentRoot, "wwwroot"))
|
|
||||||
.ConfigureServices(Configure.services)
|
.ConfigureServices(Configure.services)
|
||||||
.ConfigureLogging(Configure.logging)
|
.ConfigureLogging(Configure.logging)
|
||||||
.Configure(System.Action<IApplicationBuilder> Configure.app)
|
|
||||||
.Build()
|
|
||||||
|
|
||||||
if args.Length > 0 then
|
use app = builder.Build()
|
||||||
printfn $"Unrecognized option {args[0]}"
|
|
||||||
else
|
Configure.app app
|
||||||
app.Run()
|
|
||||||
|
let fac = app.Services.GetRequiredService<ILoggerFactory>()
|
||||||
|
let log = fac.CreateLogger "PrayerTracker"
|
||||||
|
log.LogInformation "Application Started"
|
||||||
|
|
||||||
|
app.Run()
|
||||||
|
|
||||||
|
log.LogInformation "Application Shutting Down"
|
||||||
|
|
||||||
0
|
0
|
||||||
|
@ -13,11 +13,11 @@ let toSelectList<'T> valFunc textFunc withDefault emptyText (items: 'T seq) =
|
|||||||
SelectListItem($"""— %A{s[emptyText]} —""", "")
|
SelectListItem($"""— %A{s[emptyText]} —""", "")
|
||||||
| _ -> ()
|
| _ -> ()
|
||||||
yield! items |> Seq.map (fun x -> SelectListItem(textFunc x, valFunc x)) ]
|
yield! items |> Seq.map (fun x -> SelectListItem(textFunc x, valFunc x)) ]
|
||||||
|
|
||||||
/// Create a select list from an enumeration
|
/// Create a select list from an enumeration
|
||||||
let toSelectListWithEmpty<'T> valFunc textFunc emptyText (items: 'T seq) =
|
let toSelectListWithEmpty<'T> valFunc textFunc emptyText (items: 'T seq) =
|
||||||
toSelectList valFunc textFunc true emptyText items
|
toSelectList valFunc textFunc true emptyText items
|
||||||
|
|
||||||
/// Create a select list from an enumeration
|
/// Create a select list from an enumeration
|
||||||
let toSelectListWithDefault<'T> valFunc textFunc (items: 'T seq) =
|
let toSelectListWithDefault<'T> valFunc textFunc (items: 'T seq) =
|
||||||
toSelectList valFunc textFunc true "Select" items
|
toSelectList valFunc textFunc true "Select" items
|
||||||
@ -117,7 +117,7 @@ let addInfo ctx msg =
|
|||||||
/// Add an informational HTML message to the session
|
/// Add an informational HTML message to the session
|
||||||
let addHtmlInfo ctx msg =
|
let addHtmlInfo ctx msg =
|
||||||
addUserMessage ctx { UserMessage.info with Text = htmlString msg }
|
addUserMessage ctx { UserMessage.info with Text = htmlString msg }
|
||||||
|
|
||||||
/// Add a warning message to the session
|
/// Add a warning message to the session
|
||||||
let addWarning ctx msg =
|
let addWarning ctx msg =
|
||||||
addUserMessage ctx { UserMessage.warning with Text = htmlLocString msg }
|
addUserMessage ctx { UserMessage.warning with Text = htmlLocString msg }
|
||||||
|
@ -182,13 +182,6 @@ let toHtmlIds it =
|
|||||||
let renderHtmlNode = RenderView.AsString.htmlNode
|
let renderHtmlNode = RenderView.AsString.htmlNode
|
||||||
|
|
||||||
|
|
||||||
open Giraffe.Fixi
|
|
||||||
|
|
||||||
/// Create a page link that will make the request with fixi
|
|
||||||
let pageLink href attrs content =
|
|
||||||
a (List.append [ _href href; _fxGet; _fxAction href; _fxTarget "#pt-body" ] attrs) content
|
|
||||||
|
|
||||||
|
|
||||||
open Microsoft.AspNetCore.Html
|
open Microsoft.AspNetCore.Html
|
||||||
|
|
||||||
/// Render an HTML node, then return the value as an HTML string
|
/// Render an HTML node, then return the value as an HTML string
|
||||||
@ -224,6 +217,10 @@ module TimeZones =
|
|||||||
|
|
||||||
open Giraffe.ViewEngine.Htmx
|
open Giraffe.ViewEngine.Htmx
|
||||||
|
|
||||||
|
/// Create a page link that will make the request with fixi
|
||||||
|
let pageLink href attrs content =
|
||||||
|
a (List.append [ _href href; _hxGet href ] attrs) content
|
||||||
|
|
||||||
/// Known htmx targets
|
/// Known htmx targets
|
||||||
module Target =
|
module Target =
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ let langCode () = if CultureInfo.CurrentCulture.Name.StartsWith "es" then "es" e
|
|||||||
|
|
||||||
/// Navigation items
|
/// Navigation items
|
||||||
module Navigation =
|
module Navigation =
|
||||||
|
|
||||||
/// Top navigation bar
|
/// Top navigation bar
|
||||||
let top m =
|
let top m =
|
||||||
let s = I18N.localizer.Force()
|
let s = I18N.localizer.Force()
|
||||||
@ -103,7 +103,7 @@ module Navigation =
|
|||||||
section [ _class "pt-title-bar-center"; _ariaLabel "Empty center space in top menu" ] []
|
section [ _class "pt-title-bar-center"; _ariaLabel "Empty center space in top menu" ] []
|
||||||
section [ _class "pt-title-bar-right"; _roleToolBar; _ariaLabel "Right side of top menu" ] [
|
section [ _class "pt-title-bar-right"; _roleToolBar; _ariaLabel "Right side of top menu" ] [
|
||||||
ul [] rightLinks ] ]
|
ul [] rightLinks ] ]
|
||||||
|
|
||||||
/// Identity bar (below top nav)
|
/// Identity bar (below top nav)
|
||||||
let identity m =
|
let identity m =
|
||||||
let s = I18N.localizer.Force()
|
let s = I18N.localizer.Force()
|
||||||
@ -111,7 +111,7 @@ module Navigation =
|
|||||||
div [] [
|
div [] [
|
||||||
span [ _title s["Language"].Value ] [ icon "record_voice_over"; space ]
|
span [ _title s["Language"].Value ] [ icon "record_voice_over"; space ]
|
||||||
match langCode () with
|
match langCode () with
|
||||||
| "es" ->
|
| "es" ->
|
||||||
strong [] [ locStr s["Spanish"] ]
|
strong [] [ locStr s["Spanish"] ]
|
||||||
rawText " "
|
rawText " "
|
||||||
pageLink "/language/en" [] [ locStr s["Change to English"] ]
|
pageLink "/language/en" [] [ locStr s["Change to English"] ]
|
||||||
@ -142,14 +142,14 @@ module Navigation =
|
|||||||
|
|
||||||
/// Content layouts
|
/// Content layouts
|
||||||
module Content =
|
module Content =
|
||||||
|
|
||||||
/// Content layout that tops at 60rem
|
/// Content layout that tops at 60rem
|
||||||
let standard = div [ _class "pt-content" ]
|
let standard = div [ _class "pt-content" ]
|
||||||
|
|
||||||
/// Content layout that uses the full width of the browser window
|
/// Content layout that uses the full width of the browser window
|
||||||
let wide = div [ _class "pt-content pt-full-width" ]
|
let wide = div [ _class "pt-content pt-full-width" ]
|
||||||
|
|
||||||
|
|
||||||
/// Separator for parts of the title
|
/// Separator for parts of the title
|
||||||
let private titleSep = rawText " « "
|
let private titleSep = rawText " « "
|
||||||
|
|
||||||
@ -274,14 +274,14 @@ let private partialHead pgTitle =
|
|||||||
let private pageLayout viewInfo pgTitle content =
|
let private pageLayout viewInfo pgTitle content =
|
||||||
body [] [
|
body [] [
|
||||||
Navigation.top viewInfo
|
Navigation.top viewInfo
|
||||||
div [ _id "pt-body" ] (contentSection viewInfo pgTitle content)
|
div [ _id "pt-body"; Target.content ] (contentSection viewInfo pgTitle content)
|
||||||
match viewInfo.Layout with
|
match viewInfo.Layout with
|
||||||
| FullPage ->
|
| FullPage ->
|
||||||
script [ _src "/js/ckeditor/ckeditor.js" ] []
|
script [ _src "/js/ckeditor/ckeditor.js" ] []
|
||||||
script [ _src "/_/fixi-0.5.7.js" ] []
|
Htmx.Script.minified
|
||||||
script [ _src "/_/app.js" ] []
|
script [ _src "/_/app.js" ] []
|
||||||
| _ -> () ]
|
| _ -> () ]
|
||||||
|
|
||||||
/// The standard layout(s) for PrayerTracker
|
/// The standard layout(s) for PrayerTracker
|
||||||
let standard viewInfo pageTitle content =
|
let standard viewInfo pageTitle content =
|
||||||
let s = I18N.localizer.Force()
|
let s = I18N.localizer.Force()
|
||||||
@ -328,7 +328,7 @@ let help pageTitle isHome content =
|
|||||||
div [] [
|
div [] [
|
||||||
locStr s["Language"]; rawText ": "
|
locStr s["Language"]; rawText ": "
|
||||||
match langCode () with
|
match langCode () with
|
||||||
| "es" ->
|
| "es" ->
|
||||||
locStr s["Spanish"]; rawText " • "
|
locStr s["Spanish"]; rawText " • "
|
||||||
a [ _href "/language/en" ] [ locStr s["Change to English"] ]
|
a [ _href "/language/en" ] [ locStr s["Change to English"] ]
|
||||||
| _ ->
|
| _ ->
|
||||||
@ -348,4 +348,3 @@ let help pageTitle isHome content =
|
|||||||
p [ _class "pt-center-text" ] [
|
p [ _class "pt-center-text" ] [
|
||||||
a [ _href "/help"; _title s["Help Index"].Value ] [
|
a [ _href "/help"; _title s["Help Index"].Value ] [
|
||||||
rawText "« "; locStr s["Back to Help Index"] ] ] ] ] ] ] ]
|
rawText "« "; locStr s["Back to Help Index"] ] ] ] ] ] ] ]
|
||||||
|
|
@ -15,7 +15,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Giraffe.Fixi" Version="0.5.7" />
|
|
||||||
<PackageReference Include="Giraffe.ViewEngine" Version="1.4.0" />
|
<PackageReference Include="Giraffe.ViewEngine" Version="1.4.0" />
|
||||||
<PackageReference Include="Giraffe.ViewEngine.Htmx" Version="2.0.4" />
|
<PackageReference Include="Giraffe.ViewEngine.Htmx" Version="2.0.4" />
|
||||||
<PackageReference Include="MailKit" Version="4.10.0" />
|
<PackageReference Include="MailKit" Version="4.10.0" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user