Use WoofWare.MYriad REST API entirely
All checks were successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/all-checks-complete Pipeline was successful

This commit is contained in:
Smaug123
2024-01-29 22:51:11 +00:00
parent 58fdb23719
commit 5b7a29f27f
12 changed files with 284 additions and 69 deletions

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open System open System
open PureGym open PureGym
@@ -50,7 +51,7 @@ module Authenticate =
let run (creds : UsernamePin) = let run (creds : UsernamePin) =
task { task {
let! cred = AuthToken.get creds let! cred = AuthToken.get creds CancellationToken.None
Console.WriteLine cred.AccessToken Console.WriteLine cred.AccessToken
match cred.ExpiryTime with match cred.ExpiryTime with

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open PureGym open PureGym
@@ -48,7 +49,7 @@ module Fullness =
let run (args : FullnessArgs) = let run (args : FullnessArgs) =
task { task {
let! client = Api.make args.Creds let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! id = GymSelector.canonicalId client args.Gym let! id = GymSelector.canonicalId client args.Gym
let! attendance = client.GetGymAttendance id let! attendance = client.GetGymAttendance id

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open PureGym open PureGym
@@ -44,7 +45,7 @@ module LookupGym =
let run (args : LookupGymArgs) = let run (args : LookupGymArgs) =
task { task {
let! client = Api.make args.Creds let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! s = client.GetGym 19 let! s = client.GetGym 19
System.Console.WriteLine (string<Gym> s) System.Console.WriteLine (string<Gym> s)
return 0 return 0

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open PureGym open PureGym
@@ -31,7 +32,7 @@ module MemberActivity =
let run (args : MemberActivityArgs) = let run (args : MemberActivityArgs) =
task { task {
let! client = Api.make args.Creds let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! activity = client.GetMemberActivity () let! activity = client.GetMemberActivity ()
let activity = activity.ToMemberActivity () let activity = activity.ToMemberActivity ()
System.Console.WriteLine (string<MemberActivityThisMonth> activity) System.Console.WriteLine (string<MemberActivityThisMonth> activity)

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open PureGym open PureGym
open System open System
@@ -41,7 +42,7 @@ module Sessions =
let run (args : SessionsArgs) = let run (args : SessionsArgs) =
task { task {
let! client = Api.make args.Creds let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! activity = client.GetSessions (args.FromDate, args.ToDate) let! activity = client.GetSessions (args.FromDate, args.ToDate)
System.Console.WriteLine (string<Sessions> activity) System.Console.WriteLine (string<Sessions> activity)

View File

@@ -2,26 +2,124 @@ namespace PureGym
open System open System
open System.Net.Http open System.Net.Http
open System.Threading
open System.Threading.Tasks open System.Threading.Tasks
type private CacheMessage<'a> =
| TriggerUpdate
| UpdateStored of 'a Task
| Get of AsyncReplyChannel<'a>
| Quit of AsyncReplyChannel<unit>
type Cache<'a> (obtainNew : CancellationToken -> 'a Task, expiry : 'a -> DateTime option) =
let cts = new CancellationTokenSource ()
let initialValue = obtainNew cts.Token
let rec handle (value : 'a Task) (mailbox : MailboxProcessor<CacheMessage<'a>>) : Async<unit> =
async {
let! message = mailbox.Receive ()
match message with
| Quit channel ->
channel.Reply ()
return ()
| CacheMessage.UpdateStored newValue -> return! handle newValue mailbox
| CacheMessage.TriggerUpdate ->
async {
let! a = Async.AwaitTask (obtainNew cts.Token)
let expiry = expiry a
match expiry with
| None -> return ()
| Some expiry ->
// a bit sloppy but :shrug:
do! Async.Sleep ((expiry - DateTime.Now) - TimeSpan.FromMinutes 1.0)
try
mailbox.Post CacheMessage.TriggerUpdate
with _ ->
// Post during shutdown sequence: drop it on the floor
()
return ()
}
|> fun a -> Async.Start (a, cancellationToken = cts.Token)
return! handle value mailbox
| CacheMessage.Get reply ->
let! valueAwaited = Async.AwaitTask value
reply.Reply valueAwaited
return! handle value mailbox
}
let mailbox = new MailboxProcessor<_> (handle initialValue)
do
mailbox.Start ()
mailbox.Post CacheMessage.TriggerUpdate
let isDisposing = ref 0
let hasDisposed = TaskCompletionSource<unit> ()
member this.GetCurrentValue () =
try
mailbox.PostAndAsyncReply CacheMessage.Get
with
// TODO I think this is the right exception...
| :? InvalidOperationException ->
raise (ObjectDisposedException (nameof (Cache)))
interface IDisposable with
member _.Dispose () =
if Interlocked.Increment isDisposing = 1 then
mailbox.PostAndReply CacheMessage.Quit
(mailbox :> IDisposable).Dispose ()
// We can't terminate the CTS until the mailbox has processed all client requests.
// Otherwise we terminate the mailbox's state Task before it has finished querying that
// task on behalf of clients.
cts.Cancel ()
cts.Dispose ()
hasDisposed.SetResult ()
else
hasDisposed.Task.Result
/// Methods for interacting with the PureGym REST API. /// Methods for interacting with the PureGym REST API.
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module Api = module Api =
/// Create a REST client, authenticated as the specified user.
let make (auth : Auth) : IPureGymApi Task = /// Create a REST client, authenticated as the specified user. Creds will be refreshed if possible as long as
/// the returned disposable is not disposed.
let make (auth : Auth) : (IPureGymApi * IDisposable) Task =
let cache, getToken =
match auth with
| Auth.Token t ->
{ new IDisposable with
member _.Dispose () = ()
},
fun () -> t
| Auth.User cred ->
let cache = new Cache<_> (AuthToken.get cred, _.ExpiryTime)
cache :> _, (fun () -> Async.RunSynchronously (cache.GetCurrentValue ()))
task {
let client = new HttpClient ()
client.BaseAddress <- Uri "https://capi.puregym.com/api/"
return PureGymApi.make (getToken >> _.AccessToken >> sprintf "Bearer %s") client, cache
}
/// Create a REST client, authenticated as the specified user. Do not refresh creds.
let makeWithoutRefresh (ct : CancellationToken) (auth : Auth) : IPureGymApi Task =
task { task {
let! token = let! token =
match auth with match auth with
| Auth.Token t -> Task.FromResult<_> t | Auth.Token t -> Task.FromResult<_> t
| Auth.User cred -> AuthToken.get cred | Auth.User cred -> AuthToken.get cred ct
let client = new HttpClient () let client = new HttpClient ()
client.BaseAddress <- Uri "https://capi.puregym.com/api/" client.BaseAddress <- Uri "https://capi.puregym.com/api/"
client.DefaultRequestHeaders.Authorization <- return PureGymApi.make (fun () -> $"Bearer %s{token.AccessToken}") client
Headers.AuthenticationHeaderValue ("Bearer", token.AccessToken)
client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
return PureGymApi.make client
} }

View File

@@ -5,6 +5,7 @@ open System.Collections.Generic
open System.Net.Http open System.Net.Http
open System.Text.Json open System.Text.Json
open System.Text.Json.Serialization open System.Text.Json.Serialization
open System.Threading
open System.Threading.Tasks open System.Threading.Tasks
// System.Text.Json does not support internal F# records as of .NET 8, presumably because it can't find the constructor. // System.Text.Json does not support internal F# records as of .NET 8, presumably because it can't find the constructor.
@@ -72,8 +73,9 @@ module AuthToken =
let private options = JsonSerializerOptions (IncludeFields = true) let private options = JsonSerializerOptions (IncludeFields = true)
/// Get an AuthToken for the given user email address with the given eight-digit PureGym PIN. /// Get an AuthToken for the given user email address with the given eight-digit PureGym PIN.
let get (creds : UsernamePin) : Task<AuthToken> = let get (creds : UsernamePin) (ct : CancellationToken) : Task<AuthToken> =
task { async {
let! ct = Async.CancellationToken
use client = new HttpClient () use client = new HttpClient ()
client.BaseAddress <- Uri "https://auth.puregym.com" client.BaseAddress <- Uri "https://auth.puregym.com"
client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0") client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
@@ -89,14 +91,21 @@ module AuthToken =
|> List.map KeyValuePair |> List.map KeyValuePair
use content = new FormUrlEncodedContent (request) use content = new FormUrlEncodedContent (request)
let! response = client.PostAsync (Uri "https://auth.puregym.com/connect/token", content)
let! response =
Async.AwaitTask (
client.PostAsync (Uri "https://auth.puregym.com/connect/token", content, cancellationToken = ct)
)
if response.IsSuccessStatusCode then if response.IsSuccessStatusCode then
let! content = response.Content.ReadAsStreamAsync () let! content = Async.AwaitTask (response.Content.ReadAsStreamAsync ct)
let! response = JsonSerializer.DeserializeAsync<AuthResponseRaw> (content, options)
// let! response = JsonSerializer.DeserializeAsync<AuthResponseRaw> (content, options) let! response =
Async.AwaitTask (JsonSerializer.DeserializeAsync<AuthResponseRaw>(content, options, ct).AsTask ())
return AuthToken.Parse response return AuthToken.Parse response
else else
let! content = response.Content.ReadAsStringAsync () let! content = Async.AwaitTask (response.Content.ReadAsStringAsync ct)
return failwithf $"bad status code: %+A{response.StatusCode}\n%s{content}" return failwithf $"bad status code: %+A{response.StatusCode}\n%s{content}"
} }
|> fun a -> Async.StartAsTask (a, cancellationToken = ct)

View File

@@ -10,6 +10,9 @@ open RestEase
[<WoofWare.Myriad.Plugins.HttpClient>] [<WoofWare.Myriad.Plugins.HttpClient>]
[<Header("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")>] [<Header("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")>]
type IPureGymApi = type IPureGymApi =
[<Header "Authorization">]
abstract AuthHeader : string
/// Get the complete list of all gyms known to PureGym. /// Get the complete list of all gyms known to PureGym.
[<Get "v1/gyms/">] [<Get "v1/gyms/">]
abstract GetGyms : ?ct : CancellationToken -> Task<Gym list> abstract GetGyms : ?ct : CancellationToken -> Task<Gym list>

View File

@@ -4,6 +4,8 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace PureGym namespace PureGym
open System open System
@@ -16,10 +18,12 @@ open RestEase
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module PureGymApi = module PureGymApi =
/// Create a REST client. /// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
let make (client : System.Net.Http.HttpClient) : IPureGymApi = let make (authHeader : unit -> string) (client : System.Net.Http.HttpClient) : IPureGymApi =
{ new IPureGymApi with { new IPureGymApi with
member _.GetGyms (ct : CancellationToken option) = member _.AuthHeader : string = authHeader ()
member this.GetGyms (ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
@@ -43,19 +47,21 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return node.AsArray () |> Seq.map (fun elt -> Gym.jsonParse elt) |> List.ofSeq return jsonNode.AsArray () |> Seq.map (fun elt -> Gym.jsonParse elt) |> List.ofSeq
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetMember (ct : CancellationToken option) = member this.GetMember (ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
@@ -79,19 +85,21 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return Member.jsonParse node return Member.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetGymAttendance (gymId : int, ct : CancellationToken option) = member this.GetGymAttendance (gymId : int, ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
@@ -119,19 +127,21 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return GymAttendance.jsonParse node return GymAttendance.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetGym (gymId : int, ct : CancellationToken option) = member this.GetGym (gymId : int, ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
@@ -159,19 +169,21 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return Gym.jsonParse node return Gym.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetMemberActivity (ct : CancellationToken option) = member this.GetMemberActivity (ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
@@ -195,19 +207,21 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return MemberActivityDto.jsonParse node return MemberActivityDto.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetSessions (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) = member this.GetSessions (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
@@ -238,15 +252,17 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return Sessions.jsonParse node return Sessions.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
} }

View File

@@ -3,6 +3,8 @@
// Changes to this file will be lost when the code is regenerated. // Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the GymOpeningHours type /// Module containing JSON parsing methods for the GymOpeningHours type
@@ -253,9 +255,41 @@ module Gym =
.AsValue() .AsValue()
.GetValue<string> () .GetValue<string> ()
let Location = GymLocation.jsonParse node.["location"] let Location =
let AccessOptions = GymAccessOptions.jsonParse node.["accessOptions"] GymLocation.jsonParse (
let GymOpeningHours = GymOpeningHours.jsonParse node.["gymOpeningHours"] match node.["location"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("location")
)
)
| v -> v
)
let AccessOptions =
GymAccessOptions.jsonParse (
match node.["accessOptions"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("accessOptions")
)
)
| v -> v
)
let GymOpeningHours =
GymOpeningHours.jsonParse (
match node.["gymOpeningHours"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("gymOpeningHours")
)
)
| v -> v
)
let EmailAddress = let EmailAddress =
(match node.["emailAddress"] with (match node.["emailAddress"] with
@@ -281,7 +315,17 @@ module Gym =
.AsValue() .AsValue()
.GetValue<string> () .GetValue<string> ()
let Address = GymAddress.jsonParse node.["address"] let Address =
GymAddress.jsonParse (
match node.["address"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("address")
)
)
| v -> v
)
let Status = let Status =
(match node.["status"] with (match node.["status"] with
@@ -856,7 +900,17 @@ namespace PureGym
module Visit = module Visit =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit =
let Gym = VisitGym.jsonParse node.["Gym"] let Gym =
VisitGym.jsonParse (
match node.["Gym"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Gym")
)
)
| v -> v
)
let Duration = let Duration =
(match node.["Duration"] with (match node.["Duration"] with
@@ -909,8 +963,29 @@ namespace PureGym
module SessionsSummary = module SessionsSummary =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary =
let ThisWeek = SessionsAggregate.jsonParse node.["ThisWeek"] let ThisWeek =
let Total = SessionsAggregate.jsonParse node.["Total"] SessionsAggregate.jsonParse (
match node.["ThisWeek"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("ThisWeek")
)
)
| v -> v
)
let Total =
SessionsAggregate.jsonParse (
match node.["Total"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Total")
)
)
| v -> v
)
{ {
Total = Total Total = Total
@@ -937,7 +1012,17 @@ module Sessions =
|> Seq.map (fun elt -> Visit.jsonParse elt) |> Seq.map (fun elt -> Visit.jsonParse elt)
|> List.ofSeq |> List.ofSeq
let Summary = SessionsSummary.jsonParse node.["Summary"] let Summary =
SessionsSummary.jsonParse (
match node.["Summary"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Summary")
)
)
| v -> v
)
{ {
Summary = Summary Summary = Summary

View File

@@ -6,19 +6,19 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn> <WarnOn>FS3559</WarnOn>
<WoofWareMyriadPluginVersion>1.1.13</WoofWareMyriadPluginVersion> <WoofWareMyriadPluginVersion>1.4.8</WoofWareMyriadPluginVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="String.fs" /> <Compile Include="String.fs" />
<Compile Include="Auth.fs" /> <Compile Include="Auth.fs" />
<Compile Include="Dto.fs" /> <Compile Include="Dto.fs" />
<Compile Include="GeneratedDto.fs"> <!--1--> <Compile Include="GeneratedDto.fs">
<MyriadFile>Dto.fs</MyriadFile> <!--2--> <MyriadFile>Dto.fs</MyriadFile>
</Compile> </Compile>
<Compile Include="Client.fs" /> <Compile Include="Client.fs" />
<Compile Include="GeneratedClient.fs"> <Compile Include="GeneratedClient.fs">
<MyriadFile>Client.fs</MyriadFile> <!--2--> <MyriadFile>Client.fs</MyriadFile>
</Compile> </Compile>
<Compile Include="Api.fs" /> <Compile Include="Api.fs" />
<Compile Include="GymSelector.fs" /> <Compile Include="GymSelector.fs" />
@@ -35,8 +35,7 @@
<PackageReference Update="FSharp.Core" Version="6.0.1" /> <PackageReference Update="FSharp.Core" Version="6.0.1" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="8.0.0" />
<PackageReference Include="Fastenshtein" Version="1.0.0.8" /> <PackageReference Include="Fastenshtein" Version="1.0.0.8" />
<PackageReference Include="Myriad.Core" Version="0.8.3" /> <PackageReference Include="Myriad.Sdk" Version="0.8.3" PrivateAssets="all" />
<PackageReference Include="Myriad.Sdk" Version="0.8.3" />
<PackageReference Include="WoofWare.Myriad.Plugins" Version="$(WoofWareMyriadPluginVersion)" /> <PackageReference Include="WoofWare.Myriad.Plugins" Version="$(WoofWareMyriadPluginVersion)" />
</ItemGroup> </ItemGroup>

View File

@@ -438,7 +438,7 @@
}) })
(fetchNuGet { (fetchNuGet {
pname = "WoofWare.Myriad.Plugins"; pname = "WoofWare.Myriad.Plugins";
version = "1.1.13"; version = "1.4.8";
sha256 = "sha256-TjR+3spu9vXb2kOoXM9p6yzjpt2rja1Tu7cAOmIMhog= "; sha256 = "sha256-HdqiXz4pSQ+pPkj82RsWR7zn3JePQm5/IFl4dlR2O5Y=";
}) })
] ]