- 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