From 5fd1a52bd88a9036de3c53a4a4025479b8038161 Mon Sep 17 00:00:00 2001 From: Smaug123 Date: Wed, 27 Dec 2023 20:21:08 +0000 Subject: [PATCH] WIP with JSON static parsing --- PureGym.App/AuthArg.fs | 4 +- PureGym.App/Authenticate.fs | 2 +- PureGym.App/Fullness.fs | 3 +- PureGym.App/LookupGym.fs | 2 +- PureGym.App/MemberActivity.fs | 3 +- PureGym.App/PureGym.App.fsproj | 2 +- PureGym.App/Sessions.fs | 2 +- PureGym.Test/PureGym.Test.fsproj | 7 +- PureGym.Test/TestJson.fs | 273 ++++++++++++++++++++++++++ PureGym.sln | 6 + PureGym/Client.fs | 58 ++++++ PureGym/{Api.fs => Dto.fs} | 92 +++------ PureGym/GeneratedDto.fs | 321 +++++++++++++++++++++++++++++++ PureGym/PureGym.fsproj | 17 +- PureGym/SurfaceBaseline.txt | 56 ++++-- PureGym/myriad.toml | 0 PureGym/version.json | 2 +- 17 files changed, 756 insertions(+), 94 deletions(-) create mode 100644 PureGym.Test/TestJson.fs create mode 100644 PureGym/Client.fs rename PureGym/{Api.fs => Dto.fs} (80%) create mode 100644 PureGym/GeneratedDto.fs create mode 100644 PureGym/myriad.toml diff --git a/PureGym.App/AuthArg.fs b/PureGym.App/AuthArg.fs index 0ca15ec..3866cdc 100644 --- a/PureGym.App/AuthArg.fs +++ b/PureGym.App/AuthArg.fs @@ -5,8 +5,8 @@ open PureGym type AuthArg = | [] Bearer_Token of string - | [] User_Email of string - | [] Pin of string + | [] User_Email of string + | [] Pin of string | [] Others of string interface IArgParserTemplate with diff --git a/PureGym.App/Authenticate.fs b/PureGym.App/Authenticate.fs index 2f61c36..7bb4e32 100644 --- a/PureGym.App/Authenticate.fs +++ b/PureGym.App/Authenticate.fs @@ -14,7 +14,7 @@ type GetTokenArg = match s with | GetTokenArg.Pin _ -> "Eight-digit PureGym user's PIN" | GetTokenArg.User_Email _ -> "PureGym user's email address" - | GetTokenArg.StdIn _ -> "Read anything not specified on the command line from stdin" + | GetTokenArg.StdIn -> "Read anything not specified on the command line from stdin" static member Parse (args : ParseResults) : Result = let canUseStdin = args.TryGetResult(GetTokenArg.StdIn).IsSome diff --git a/PureGym.App/Fullness.fs b/PureGym.App/Fullness.fs index 749498c..ab34bf5 100644 --- a/PureGym.App/Fullness.fs +++ b/PureGym.App/Fullness.fs @@ -48,9 +48,10 @@ module Fullness = let run (args : FullnessArgs) = task { - let! client = Api.make args.Creds + let! client = Dto.make args.Creds let! id = GymSelector.canonicalId client args.Gym let! attendance = client.GetGymAttendance id + let attendance = failwith "" if args.Terse then System.Console.WriteLine attendance.TotalPeopleInGym diff --git a/PureGym.App/LookupGym.fs b/PureGym.App/LookupGym.fs index 2ca9a82..34df497 100644 --- a/PureGym.App/LookupGym.fs +++ b/PureGym.App/LookupGym.fs @@ -44,7 +44,7 @@ module LookupGym = let run (args : LookupGymArgs) = task { - let! client = Api.make args.Creds + let! client = Dto.make args.Creds let! s = client.GetGym 19 System.Console.WriteLine (string s) return 0 diff --git a/PureGym.App/MemberActivity.fs b/PureGym.App/MemberActivity.fs index 98138e7..c9803b1 100644 --- a/PureGym.App/MemberActivity.fs +++ b/PureGym.App/MemberActivity.fs @@ -31,9 +31,8 @@ module MemberActivity = let run (args : MemberActivityArgs) = task { - let! client = Api.make args.Creds + let! client = Dto.make args.Creds let! activity = client.GetMemberActivity () - let activity = activity.ToMemberActivity () System.Console.WriteLine (string activity) return 0 } diff --git a/PureGym.App/PureGym.App.fsproj b/PureGym.App/PureGym.App.fsproj index 0a7b218..2422fb1 100644 --- a/PureGym.App/PureGym.App.fsproj +++ b/PureGym.App/PureGym.App.fsproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/PureGym.App/Sessions.fs b/PureGym.App/Sessions.fs index 4e641f6..86d8d2d 100644 --- a/PureGym.App/Sessions.fs +++ b/PureGym.App/Sessions.fs @@ -41,7 +41,7 @@ module Sessions = let run (args : SessionsArgs) = task { - let! client = Api.make args.Creds + let! client = Dto.make args.Creds let! activity = client.GetSessions args.FromDate args.ToDate System.Console.WriteLine (string activity) diff --git a/PureGym.Test/PureGym.Test.fsproj b/PureGym.Test/PureGym.Test.fsproj index 05ad172..1624b9b 100644 --- a/PureGym.Test/PureGym.Test.fsproj +++ b/PureGym.Test/PureGym.Test.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false true @@ -9,12 +9,15 @@ + + + - + diff --git a/PureGym.Test/TestJson.fs b/PureGym.Test/TestJson.fs new file mode 100644 index 0000000..a01f8c2 --- /dev/null +++ b/PureGym.Test/TestJson.fs @@ -0,0 +1,273 @@ +namespace PureGym.Test + +open System +open System.Text.Json.Nodes +open NUnit.Framework +open FsUnitTyped +open PureGym + +[] +module TestJson = + + let gymOpeningHoursCases = + [ + """{"openingHours": [], "isAlwaysOpen": false}""", { GymOpeningHours.OpeningHours = [] ; IsAlwaysOpen = false } + """{"openingHours": ["something"], "isAlwaysOpen": false}""", { GymOpeningHours.OpeningHours = ["something"] ; IsAlwaysOpen = false } + ] + |> List.map TestCaseData + + [] + let ``GymOpeningHours JSON parse`` (json : string, expected : GymOpeningHours) = + JsonNode.Parse json + |> GymOpeningHours.jsonParse + |> shouldEqual expected + + let gymAccessOptionsCases = + List.allPairs [ true ; false ] [ true ; false ] + |> List.map (fun (a, b) -> + let s = sprintf """{"pinAccess": %b, "qrCodeAccess": %b}""" a b + s, { GymAccessOptions.PinAccess = a ; QrCodeAccess = b } + ) + |> List.map TestCaseData + + [] + let ``GymAccessOptions JSON parse`` (json : string, expected : GymAccessOptions) = + JsonNode.Parse json + |> GymAccessOptions.jsonParse + |> shouldEqual expected + + let gymLocationCases = + [ + """{"latitude": 1.0, "longitude": 3.0}""", { GymLocation.Latitude = 1.0 ; Longitude = 3.0 } + ] + |> List.map TestCaseData + + [] + let ``GymLocation JSON parse`` (json : string, expected : GymLocation) = + JsonNode.Parse json + |> GymLocation.jsonParse + |> shouldEqual expected + + let gymAddressCases = + [ + """{"addressLine1": "", "postCode": "hi", "town": ""}""", { GymAddress.AddressLine1 = "" ; AddressLine2 = None ; AddressLine3 = None ; County = None ; Postcode = "hi" ; Town = "" } + """{"addressLine1": "", "addressLine2": null, "postCode": "hi", "town": ""}""", { GymAddress.AddressLine1 = "" ; AddressLine2 = None ; AddressLine3 = None ; County = None ; Postcode = "hi" ; Town = "" } + ] + |> List.map TestCaseData + + [] + let ``GymAddress JSON parse`` (json : string, expected : GymAddress) = + JsonNode.Parse (json, Nullable (JsonNodeOptions(PropertyNameCaseInsensitive = true))) + |> GymAddress.jsonParse + |> shouldEqual expected + + let gymCases = + let ovalJson = """{"name":"London Oval","id":19,"status":2,"address":{"addressLine1":"Canterbury Court","addressLine2":"Units 4, 4A, 5 And 5A","addressLine3":"Kennington Park","town":"LONDON","county":null,"postcode":"SW9 6DE"},"phoneNumber":"+44 3444770005","emailAddress":"info.londonoval@puregym.com","staffMembers":null,"gymOpeningHours":{"isAlwaysOpen":true,"openingHours":[]},"reasonsToJoin":null,"accessOptions":{"pinAccess":true,"qrCodeAccess":true},"virtualTourUrl":null,"personalTrainersUrl":null,"webViewUrl":null,"floorPlanUrl":null,"location":{"longitude":"-0.110252","latitude":"51.480401"},"timeZone":"Europe/London","reopenDate":"2021-04-12T00:00:00+01 Europe/London"}""" + let oval = + { + Gym.Name = "London Oval" + Id = 19 + Status = 2 + Address = + { + AddressLine1 = "Canterbury Court" + AddressLine2 = Some "Units 4, 4A, 5 And 5A" + AddressLine3 = Some "Kennington Park" + Town = "LONDON" + County = None + Postcode = "SW9 6DE" + } + PhoneNumber = "+44 3444770005" + EmailAddress = "info.londonoval@puregym.com" + GymOpeningHours = + { + IsAlwaysOpen = true + OpeningHours = [] + } + AccessOptions = { PinAccess = true ; QrCodeAccess = true } + Location = { Longitude = -0.110252 ; Latitude = 51.480401 } + TimeZone = "Europe/London" + ReopenDate = "2021-04-12T00:00:00+01 Europe/London" + } + [ + ovalJson, oval + ] + |> List.map TestCaseData + + [] + let ``Gym JSON parse`` (json : string, expected : Gym) = + JsonNode.Parse json + |> Gym.jsonParse + |> shouldEqual expected + + let memberCases = + let me = + { + Id = 1234567 + CompoundMemberId = "12A123456" + FirstName = "Patrick" + LastName = "Stevens" + HomeGymId = 19 + HomeGymName = "London Oval" + EmailAddress = "someone@somewhere" + GymAccessPin = "00000000" + DateOfBirth = DateOnly (1994, 01, 02) + MobileNumber = "+44 1234567" + Postcode = "W1A 1AA" + MembershipName = "Corporate" + MembershipLevel = 12 + SuspendedReason = 0 + MemberStatus = 2 + } + let meJson = """{ + "id": 1234567, + "compoundMemberId": "12A123456", + "firstName": "Patrick", + "lastName": "Stevens", + "homeGymId": 19, + "homeGymName": "London Oval", + "emailAddress": "someone@somewhere", + "gymAccessPin": "00000000", + "dateofBirth": "1994-01-02", + "mobileNumber": "+44 1234567", + "postCode": "W1A 1AA", + "membershipName": "Corporate", + "membershipLevel": 12, + "suspendedReason": 0, + "memberStatus": 2 +}""" + [ + meJson, me + ] + |> List.map TestCaseData + + [] + let ``Member JSON parse`` (json : string, expected : Member) = + json + |> JsonNode.Parse + |> Member.jsonParse + |> shouldEqual expected + + let gymAttendanceCases = + let json = """{ + "description": "65", + "totalPeopleInGym": 65, + "totalPeopleInClasses": 2, + "totalPeopleSuffix": null, + "isApproximate": false, + "attendanceTime": "2023-12-27T18:54:09.5101697", + "lastRefreshed": "2023-12-27T18:54:09.5101697Z", + "lastRefreshedPeopleInClasses": "2023-12-27T18:50:26.0782286Z", + "maximumCapacity": 0 +}""" + let expected = + { + Description = "65" + TotalPeopleInGym = 65 + TotalPeopleInClasses = 2 + TotalPeopleSuffix = None + IsApproximate = false + AttendanceTime = DateTime (2023, 12, 27, 18, 54, 09, 510, 169, DateTimeKind.Utc) + TimeSpan.FromTicks 7L + LastRefreshed = DateTime (2023, 12, 27, 18, 54, 09, 510, 169, DateTimeKind.Utc) + TimeSpan.FromTicks 7L + LastRefreshedPeopleInClasses = DateTime (2023, 12, 27, 18, 50, 26, 078, 228, DateTimeKind.Utc) + TimeSpan.FromTicks 6L + MaximumCapacity = 0 + } + [ + json, expected + ] + |> List.map TestCaseData + + [] + let ``GymAttendance JSON parse`` (json : string, expected : GymAttendance) = + json + |> JsonNode.Parse + |> GymAttendance.jsonParse + |> shouldEqual expected + + let memberActivityDtoCases = + let json = """{"totalDuration":2217,"averageDuration":48,"totalVisits":46,"totalClasses":0,"isEstimated":false,"lastRefreshed":"2023-12-27T19:00:56.0309892Z"}""" + let value = { + TotalDuration = 2217 + AverageDuration = 48 + TotalVisits = 46 + TotalClasses = 0 + IsEstimated = false + LastRefreshed = DateTime (2023, 12, 27, 19, 00, 56, 030, 989, DateTimeKind.Utc) + TimeSpan.FromTicks 2L + } + [ + json, value + ] + |> List.map TestCaseData + + [] + let ``MemberActivityDto JSON parse`` (json : string, expected : MemberActivityDto) = + json + |> JsonNode.Parse + |> MemberActivityDto.jsonParse + |> shouldEqual expected + + let sessionsCases = + let json = """{ + "Summary":{"Total":{"Activities":0,"Visits":10,"Duration":445},"ThisWeek":{"Activities":0,"Visits":0,"Duration":0}}, + "Visits":[ + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-21T10:12:00","Duration":50,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-20T12:05:00","Duration":80,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-17T19:37:00","Duration":46,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-16T12:19:00","Duration":37,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-15T11:14:00","Duration":47,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-13T10:30:00","Duration":36,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-10T16:18:00","Duration":32,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-05T22:36:00","Duration":40,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-03T17:59:00","Duration":48,"Name":null}, + {"IsDurationEstimated":false,"Gym":{"Id":19,"Name":"London Oval","Status":"Blocked","Location":null,"GymAccess":null,"ContactInfo":null,"TimeZone":null},"StartTime":"2023-12-01T21:41:00","Duration":29,"Name":null}], + "Activities":[]} +""" + let singleVisit startTime duration = + { + IsDurationEstimated = false + Gym = { + Id = 19 + Name = "London Oval" + Status = "Blocked" + } + StartTime = startTime + Duration = duration + } + let expected = { + Summary = { + Total = { + Activities = 0 + Visits = 10 + Duration = 445 + } + ThisWeek = { + Activities = 0 + Visits = 0 + Duration = 0 + } + } + Visits = + [ + singleVisit (DateTime (2023, 12, 21, 10, 12, 00)) 50 + singleVisit (DateTime (2023, 12, 20, 12, 05, 00)) 80 + singleVisit (DateTime (2023, 12, 17, 19, 37, 00)) 46 + singleVisit (DateTime (2023, 12, 16, 12, 19, 00)) 37 + singleVisit (DateTime (2023, 12, 15, 11, 14, 00)) 47 + singleVisit (DateTime (2023, 12, 13, 10, 30, 00)) 36 + singleVisit (DateTime (2023, 12, 10, 16, 18, 00)) 32 + singleVisit (DateTime (2023, 12, 05, 22, 36, 00)) 40 + singleVisit (DateTime (2023, 12, 03, 17, 59, 00)) 48 + singleVisit (DateTime (2023, 12, 01, 21, 41, 00)) 29 + ] + } + [ + json, expected + ] + |> List.map TestCaseData + + [] + let ``Sessions JSON parse`` (json : string, expected : Sessions) = + json + |> fun o -> JsonNode.Parse (o, Nullable (JsonNodeOptions (PropertyNameCaseInsensitive = true))) + |> Sessions.jsonParse + |> shouldEqual expected diff --git a/PureGym.sln b/PureGym.sln index 034b8a5..4e652ed 100644 --- a/PureGym.sln +++ b/PureGym.sln @@ -6,6 +6,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PureGym.App", "PureGym.App\ EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PureGym.Test", "PureGym.Test\PureGym.Test.fsproj", "{F09DF609-5F53-4BB3-BD64-DDB136CD4D2E}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MyriadPlugin", "..\MyriadPlugin\MyriadPlugin\MyriadPlugin.fsproj", "{5D1BEE42-EA5E-4F1B-8CDA-37846E68D76E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +26,9 @@ Global {F09DF609-5F53-4BB3-BD64-DDB136CD4D2E}.Debug|Any CPU.Build.0 = Debug|Any CPU {F09DF609-5F53-4BB3-BD64-DDB136CD4D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU {F09DF609-5F53-4BB3-BD64-DDB136CD4D2E}.Release|Any CPU.Build.0 = Release|Any CPU + {5D1BEE42-EA5E-4F1B-8CDA-37846E68D76E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D1BEE42-EA5E-4F1B-8CDA-37846E68D76E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D1BEE42-EA5E-4F1B-8CDA-37846E68D76E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D1BEE42-EA5E-4F1B-8CDA-37846E68D76E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/PureGym/Client.fs b/PureGym/Client.fs new file mode 100644 index 0000000..db57c37 --- /dev/null +++ b/PureGym/Client.fs @@ -0,0 +1,58 @@ +namespace PureGym + +open System +open System.Net.Http +open System.Threading.Tasks +open RestEase + +/// The PureGym REST API. You probably want to instantiate one of these with `Api.make`. +[] +type IPureGymApi = + /// Get the complete list of all gyms known to PureGym. + [] + abstract GetGyms : unit -> Task + + /// Get information about the PureGym human whose credentials this client is authenticated with. + [] + abstract GetMember : unit -> Task + + /// Get information about how full the given gym currently is. The gym ID can be found from `GetGyms`. + [] + abstract GetGymAttendance : [] gymId : int -> Task + + /// Get information about a specific gym. + [] + abstract GetGym : [] gymId : int -> Task + + /// Get information about the activities logged against the currently authenticated PureGym human. + [] + abstract GetMemberActivity : unit -> Task + + /// Get information about the individual visits to all PureGyms the currently-authenticated PureGym human has made. + [] + abstract GetSessions : [] fromDate : DateTime -> [] toDate : DateTime -> Task + +// [] +// abstract GetMemberActivityAll : unit -> Task + +/// Methods for interacting with the PureGym REST API. +[] +module Dto = + /// Create a REST client, authenticated as the specified user. + let make (auth : Auth) : IPureGymApi Task = + task { + let! token = + match auth with + | Auth.Token t -> Task.FromResult<_> t + | Auth.User cred -> AuthToken.get cred + + let client = new HttpClient () + client.BaseAddress <- Uri "https://capi.puregym.com/api" + + client.DefaultRequestHeaders.Authorization <- + Headers.AuthenticationHeaderValue ("Bearer", token.AccessToken) + + client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0") + + return RestClient.For client + } diff --git a/PureGym/Api.fs b/PureGym/Dto.fs similarity index 80% rename from PureGym/Api.fs rename to PureGym/Dto.fs index 6ff4793..6a70891 100644 --- a/PureGym/Api.fs +++ b/PureGym/Dto.fs @@ -1,12 +1,10 @@ namespace PureGym open System -open System.Net.Http open System.Text.Json.Serialization -open System.Threading.Tasks -open RestEase /// Describes the opening hours of a given gym. +[] type GymOpeningHours = { /// If this is true, there should be no OpeningHours (but nothing enforces that). @@ -23,6 +21,7 @@ type GymOpeningHours = this.OpeningHours |> String.concat ", " /// How a human can authenticate with a gym when they physically try to enter it +[] type GymAccessOptions = { /// This gym has PIN entry pads @@ -36,28 +35,32 @@ type GymAccessOptions = $"Pin access: %c{Char.emoji this.PinAccess}; QR code access: %c{Char.emoji this.QrCodeAccess}" /// Where a gym is on the Earth +[] type GymLocation = { /// Measured in degrees + [] Longitude : float /// Measured in degrees + [] Latitude : float } /// The postal address of a gym +[] type GymAddress = { /// E.g. "Canterbury Court" [] AddressLine1 : string /// E.g. "Units 4, 4A, 5 And 5A" - AddressLine2 : string + AddressLine2 : string option /// E.g. "Kennington Park" - AddressLine3 : string + AddressLine3 : string option /// E.g. "LONDON" [] Town : string - County : string + County : string option /// E.g. "SW9 6DE" [] Postcode : string @@ -67,11 +70,11 @@ type GymAddress = override this.ToString () = [ yield Some this.AddressLine1 - yield this.AddressLine2 |> Option.ofObj - yield this.AddressLine3 |> Option.ofObj + yield this.AddressLine2 + yield this.AddressLine3 match this.County with - | null -> yield Some $"%s{this.Town} %s{this.Postcode}" - | county -> + | None -> yield Some $"%s{this.Town} %s{this.Postcode}" + | Some county -> yield Some this.Town yield Some $"%s{county} %s{this.Postcode}" ] @@ -79,6 +82,7 @@ type GymAddress = |> String.concat "\n" /// Metadata about a physical gym +[] type Gym = { // The following fields are returned but are always null @@ -133,6 +137,7 @@ Opening hours: %s{string this.GymOpeningHours} """ /// A human member of PureGym +[] type Member = { /// This member's ID. This is a fairly large number. @@ -153,10 +158,12 @@ type Member = /// This user's gym access pin, probably 8 digits GymAccessPin : string /// This user's recorded date of birth + [] DateOfBirth : DateOnly /// This user's phone number, human-readable MobileNumber : string /// This user's registered home postcode + [] Postcode : string /// E.g. "Corporate" MembershipName : string @@ -166,6 +173,7 @@ type Member = } /// Statistics for how many people are currently at a gym +[] type GymAttendance = { /// This appears always to be just equal to TotalPeopleInGym, but a string. @@ -178,7 +186,7 @@ type GymAttendance = [] TotalPeopleInClasses : int /// E.g. " or fewer" - TotalPeopleSuffix : string + TotalPeopleSuffix : string option [] IsApproximate : bool /// When the query was received (I think) @@ -195,8 +203,8 @@ type GymAttendance = override this.ToString () = let totalPeopleSuffix = match this.TotalPeopleSuffix with - | null -> "" - | suffix -> suffix + | None -> "" + | Some suffix -> suffix let capacity = if this.MaximumCapacity = 0 then @@ -234,6 +242,7 @@ type MemberActivityThisMonth = } /// Don't use this type. It's public because System.Text.Json can't do private types. +[] type MemberActivityDto = { [] @@ -260,6 +269,7 @@ type MemberActivityDto = LastRefreshed = this.LastRefreshed } +[] type SessionsAggregate = { /// Number of gym "activities" within some query-defined time period; presumably this is like classes? @@ -272,6 +282,7 @@ type SessionsAggregate = } /// The DTO for gym info returned from the Sessions endpoint. +[] type VisitGym = { // Omitting Location, GymAccess, ContactInfo, TimeZone because these were all null for me @@ -284,6 +295,7 @@ type VisitGym = } /// Summary of a single visit to a gym. +[] type Visit = { // Omitted Name because it always was null for me @@ -303,6 +315,7 @@ type Visit = $"%s{this.Gym.Name}: %s{startTime} (%i{this.Duration} minutes)" /// Aggregate statistics for gym visits across a time period. +[] type SessionsSummary = { /// Aggregate stats for gym visits within the query-dependent time period. @@ -315,6 +328,7 @@ type SessionsSummary = override this.ToString () = $"%i{this.Total.Visits} visits, totalling %i{this.Total.Duration} minutes" +[] type Sessions = { Summary : SessionsSummary @@ -327,55 +341,3 @@ type Sessions = let visits = this.Visits |> Seq.map string |> String.concat "\n" $"%s{summary}\n%s{visits}" - -/// The PureGym REST API. You probably want to instantiate one of these with `Api.make`. -[] -type IPureGymApi = - /// Get the complete list of all gyms known to PureGym. - [] - abstract GetGyms : unit -> Task - - /// Get information about the PureGym human whose credentials this client is authenticated with. - [] - abstract GetMember : unit -> Task - - /// Get information about how full the given gym currently is. The gym ID can be found from `GetGyms`. - [] - abstract GetGymAttendance : [] gymId : int -> Task - - /// Get information about a specific gym. - [] - abstract GetGym : [] gymId : int -> Task - - /// Get information about the activities logged against the currently authenticated PureGym human. - [] - abstract GetMemberActivity : unit -> Task - - /// Get information about the individual visits to all PureGyms the currently-authenticated PureGym human has made. - [] - abstract GetSessions : [] fromDate : DateTime -> [] toDate : DateTime -> Task - -// [] -// abstract GetMemberActivityAll : unit -> Task - -/// Methods for interacting with the PureGym REST API. -[] -module Api = - /// Create a REST client, authenticated as the specified user. - let make (auth : Auth) : IPureGymApi Task = - task { - let! token = - match auth with - | Auth.Token t -> Task.FromResult<_> t - | Auth.User cred -> AuthToken.get cred - - let client = new HttpClient () - client.BaseAddress <- Uri "https://capi.puregym.com/api" - - client.DefaultRequestHeaders.Authorization <- - Headers.AuthenticationHeaderValue ("Bearer", token.AccessToken) - - client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0") - - return RestClient.For client - } diff --git a/PureGym/GeneratedDto.fs b/PureGym/GeneratedDto.fs new file mode 100644 index 0000000..a981095 --- /dev/null +++ b/PureGym/GeneratedDto.fs @@ -0,0 +1,321 @@ +//------------------------------------------------------------------------------ +// This code was generated by myriad. +// Changes to this file will be lost when the code is regenerated. +//------------------------------------------------------------------------------ + +namespace PureGym + +/// Module containing JSON parsing methods for the GymOpeningHours type +[] +[] +module GymOpeningHours = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : GymOpeningHours = + let OpeningHours = + node.["openingHours"].AsArray() + |> Seq.map (fun elt -> elt.AsValue().GetValue()) + |> List.ofSeq + + let IsAlwaysOpen = node.["isAlwaysOpen"].AsValue().GetValue() + + { IsAlwaysOpen = IsAlwaysOpen + OpeningHours = OpeningHours } +namespace PureGym + +/// Module containing JSON parsing methods for the GymAccessOptions type +[] +[] +module GymAccessOptions = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : GymAccessOptions = + let QrCodeAccess = node.["qrCodeAccess"].AsValue().GetValue() + let PinAccess = node.["pinAccess"].AsValue().GetValue() + + { PinAccess = PinAccess + QrCodeAccess = QrCodeAccess } +namespace PureGym + +/// Module containing JSON parsing methods for the GymLocation type +[] +[] +module GymLocation = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : GymLocation = + let Latitude = + try + node.["latitude"].AsValue().GetValue() + with :? System.InvalidOperationException as exc -> + if exc.Message.Contains "cannot be converted to" then + if + System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString + then + node.["latitude"].AsValue().GetValue() |> System.Double.Parse + else + reraise () + else + reraise () + + let Longitude = + try + node.["longitude"].AsValue().GetValue() + with :? System.InvalidOperationException as exc -> + if exc.Message.Contains "cannot be converted to" then + if + System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString + then + node.["longitude"].AsValue().GetValue() |> System.Double.Parse + else + reraise () + else + reraise () + + { Longitude = Longitude + Latitude = Latitude } +namespace PureGym + +/// Module containing JSON parsing methods for the GymAddress type +[] +[] +module GymAddress = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : GymAddress = + let Postcode = node.["postcode"].AsValue().GetValue() + + let County = + match node.["county"] with + | null -> None + | v -> v.AsValue().GetValue() |> Some + + let Town = node.["town"].AsValue().GetValue() + + let AddressLine3 = + match node.["addressLine3"] with + | null -> None + | v -> v.AsValue().GetValue() |> Some + + let AddressLine2 = + match node.["addressLine2"] with + | null -> None + | v -> v.AsValue().GetValue() |> Some + + let AddressLine1 = node.["addressLine1"].AsValue().GetValue() + + { AddressLine1 = AddressLine1 + AddressLine2 = AddressLine2 + AddressLine3 = AddressLine3 + Town = Town + County = County + Postcode = Postcode } +namespace PureGym + +/// Module containing JSON parsing methods for the Gym type +[] +[] +module Gym = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : Gym = + let ReopenDate = node.["reopenDate"].AsValue().GetValue() + let TimeZone = node.["timeZone"].AsValue().GetValue() + let Location = GymLocation.jsonParse node.["location"] + let AccessOptions = GymAccessOptions.jsonParse node.["accessOptions"] + let GymOpeningHours = GymOpeningHours.jsonParse node.["gymOpeningHours"] + let EmailAddress = node.["emailAddress"].AsValue().GetValue() + let PhoneNumber = node.["phoneNumber"].AsValue().GetValue() + let Address = GymAddress.jsonParse node.["address"] + let Status = node.["status"].AsValue().GetValue() + let Id = node.["id"].AsValue().GetValue() + let Name = node.["name"].AsValue().GetValue() + + { Name = Name + Id = Id + Status = Status + Address = Address + PhoneNumber = PhoneNumber + EmailAddress = EmailAddress + GymOpeningHours = GymOpeningHours + AccessOptions = AccessOptions + Location = Location + TimeZone = TimeZone + ReopenDate = ReopenDate } +namespace PureGym + +/// Module containing JSON parsing methods for the Member type +[] +[] +module Member = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : Member = + let MemberStatus = node.["memberStatus"].AsValue().GetValue() + let SuspendedReason = node.["suspendedReason"].AsValue().GetValue() + let MembershipLevel = node.["membershipLevel"].AsValue().GetValue() + let MembershipName = node.["membershipName"].AsValue().GetValue() + let Postcode = node.["postCode"].AsValue().GetValue() + let MobileNumber = node.["mobileNumber"].AsValue().GetValue() + + let DateOfBirth = + node.["dateofBirth"].AsValue().GetValue() |> System.DateOnly.Parse + + let GymAccessPin = node.["gymAccessPin"].AsValue().GetValue() + let EmailAddress = node.["emailAddress"].AsValue().GetValue() + let HomeGymName = node.["homeGymName"].AsValue().GetValue() + let HomeGymId = node.["homeGymId"].AsValue().GetValue() + let LastName = node.["lastName"].AsValue().GetValue() + let FirstName = node.["firstName"].AsValue().GetValue() + let CompoundMemberId = node.["compoundMemberId"].AsValue().GetValue() + let Id = node.["id"].AsValue().GetValue() + + { Id = Id + CompoundMemberId = CompoundMemberId + FirstName = FirstName + LastName = LastName + HomeGymId = HomeGymId + HomeGymName = HomeGymName + EmailAddress = EmailAddress + GymAccessPin = GymAccessPin + DateOfBirth = DateOfBirth + MobileNumber = MobileNumber + Postcode = Postcode + MembershipName = MembershipName + MembershipLevel = MembershipLevel + SuspendedReason = SuspendedReason + MemberStatus = MemberStatus } +namespace PureGym + +/// Module containing JSON parsing methods for the GymAttendance type +[] +[] +module GymAttendance = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : GymAttendance = + let MaximumCapacity = node.["maximumCapacity"].AsValue().GetValue() + + let LastRefreshedPeopleInClasses = + node.["lastRefreshedPeopleInClasses"].AsValue().GetValue() + |> System.DateTime.Parse + + let LastRefreshed = + node.["lastRefreshed"].AsValue().GetValue() |> System.DateTime.Parse + + let AttendanceTime = + node.["attendanceTime"].AsValue().GetValue() |> System.DateTime.Parse + + let IsApproximate = node.["isApproximate"].AsValue().GetValue() + + let TotalPeopleSuffix = + match node.["totalPeopleSuffix"] with + | null -> None + | v -> v.AsValue().GetValue() |> Some + + let TotalPeopleInClasses = node.["totalPeopleInClasses"].AsValue().GetValue() + let TotalPeopleInGym = node.["totalPeopleInGym"].AsValue().GetValue() + let Description = node.["description"].AsValue().GetValue() + + { Description = Description + TotalPeopleInGym = TotalPeopleInGym + TotalPeopleInClasses = TotalPeopleInClasses + TotalPeopleSuffix = TotalPeopleSuffix + IsApproximate = IsApproximate + AttendanceTime = AttendanceTime + LastRefreshed = LastRefreshed + LastRefreshedPeopleInClasses = LastRefreshedPeopleInClasses + MaximumCapacity = MaximumCapacity } +namespace PureGym + +/// Module containing JSON parsing methods for the MemberActivityDto type +[] +[] +module MemberActivityDto = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : MemberActivityDto = + let LastRefreshed = + node.["lastRefreshed"].AsValue().GetValue() |> System.DateTime.Parse + + let IsEstimated = node.["isEstimated"].AsValue().GetValue() + let TotalClasses = node.["totalClasses"].AsValue().GetValue() + let TotalVisits = node.["totalVisits"].AsValue().GetValue() + let AverageDuration = node.["averageDuration"].AsValue().GetValue() + let TotalDuration = node.["totalDuration"].AsValue().GetValue() + + { TotalDuration = TotalDuration + AverageDuration = AverageDuration + TotalVisits = TotalVisits + TotalClasses = TotalClasses + IsEstimated = IsEstimated + LastRefreshed = LastRefreshed } +namespace PureGym + +/// Module containing JSON parsing methods for the SessionsAggregate type +[] +[] +module SessionsAggregate = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : SessionsAggregate = + let Duration = node.["duration"].AsValue().GetValue() + let Visits = node.["visits"].AsValue().GetValue() + let Activities = node.["activities"].AsValue().GetValue() + + { Activities = Activities + Visits = Visits + Duration = Duration } +namespace PureGym + +/// Module containing JSON parsing methods for the VisitGym type +[] +[] +module VisitGym = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : VisitGym = + let Status = node.["status"].AsValue().GetValue() + let Name = node.["name"].AsValue().GetValue() + let Id = node.["id"].AsValue().GetValue() + + { Id = Id + Name = Name + Status = Status } +namespace PureGym + +/// Module containing JSON parsing methods for the Visit type +[] +[] +module Visit = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : Visit = + let Gym = VisitGym.jsonParse node.["gym"] + let Duration = node.["duration"].AsValue().GetValue() + + let StartTime = + node.["startTime"].AsValue().GetValue() |> System.DateTime.Parse + + let IsDurationEstimated = node.["isDurationEstimated"].AsValue().GetValue() + + { IsDurationEstimated = IsDurationEstimated + StartTime = StartTime + Duration = Duration + Gym = Gym } +namespace PureGym + +/// Module containing JSON parsing methods for the SessionsSummary type +[] +[] +module SessionsSummary = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : SessionsSummary = + let ThisWeek = SessionsAggregate.jsonParse node.["thisWeek"] + let Total = SessionsAggregate.jsonParse node.["total"] + { Total = Total; ThisWeek = ThisWeek } +namespace PureGym + +/// Module containing JSON parsing methods for the Sessions type +[] +[] +module Sessions = + /// Parse from a JSON node. + let jsonParse (node: System.Text.Json.Nodes.JsonNode) : Sessions = + let Visits = + node.["visits"].AsArray() + |> Seq.map (fun elt -> Visit.jsonParse elt) + |> List.ofSeq + + let Summary = SessionsSummary.jsonParse node.["summary"] + { Summary = Summary; Visits = Visits } + diff --git a/PureGym/PureGym.fsproj b/PureGym/PureGym.fsproj index 7523f84..b101093 100644 --- a/PureGym/PureGym.fsproj +++ b/PureGym/PureGym.fsproj @@ -8,17 +8,30 @@ - + + + Dto.fs + + + + + - + + + + + + + diff --git a/PureGym/SurfaceBaseline.txt b/PureGym/SurfaceBaseline.txt index 5102d5c..1701c9a 100644 --- a/PureGym/SurfaceBaseline.txt +++ b/PureGym/SurfaceBaseline.txt @@ -1,5 +1,3 @@ -PureGym.Api inherit obj -PureGym.Api.make [static method]: PureGym.Auth -> PureGym.IPureGymApi System.Threading.Tasks.Task PureGym.Auth inherit obj, implements PureGym.Auth System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Auth System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 2 cases PureGym.Auth+Tags inherit obj PureGym.Auth+Tags.Token [static field]: int = 1 @@ -37,6 +35,8 @@ PureGym.AuthToken.get_ExpiryTime [method]: unit -> System.DateTime option PureGym.AuthTokenModule inherit obj PureGym.AuthTokenModule.get [static method]: PureGym.UsernamePin -> PureGym.AuthToken System.Threading.Tasks.Task PureGym.AuthTokenModule.ofBearerToken [static method]: string -> PureGym.AuthToken +PureGym.Dto inherit obj +PureGym.Dto.make [static method]: PureGym.Auth -> PureGym.IPureGymApi System.Threading.Tasks.Task PureGym.Gym inherit obj, implements PureGym.Gym System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Gym System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.Gym..ctor [constructor]: (string, int, int, PureGym.GymAddress, string, string, PureGym.GymOpeningHours, PureGym.GymAccessOptions, PureGym.GymLocation, string, string) PureGym.Gym.AccessOptions [property]: [read-only] PureGym.GymAccessOptions @@ -67,22 +67,26 @@ PureGym.GymAccessOptions.get_PinAccess [method]: unit -> bool PureGym.GymAccessOptions.get_QrCodeAccess [method]: unit -> bool PureGym.GymAccessOptions.PinAccess [property]: [read-only] bool PureGym.GymAccessOptions.QrCodeAccess [property]: [read-only] bool +PureGym.GymAccessOptionsModule inherit obj +PureGym.GymAccessOptionsModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.GymAccessOptions PureGym.GymAddress inherit obj, implements PureGym.GymAddress System.IEquatable, System.Collections.IStructuralEquatable, PureGym.GymAddress System.IComparable, System.IComparable, System.Collections.IStructuralComparable -PureGym.GymAddress..ctor [constructor]: (string, string, string, string, string, string) +PureGym.GymAddress..ctor [constructor]: (string, string option, string option, string, string option, string) PureGym.GymAddress.AddressLine1 [property]: [read-only] string -PureGym.GymAddress.AddressLine2 [property]: [read-only] string -PureGym.GymAddress.AddressLine3 [property]: [read-only] string -PureGym.GymAddress.County [property]: [read-only] string +PureGym.GymAddress.AddressLine2 [property]: [read-only] string option +PureGym.GymAddress.AddressLine3 [property]: [read-only] string option +PureGym.GymAddress.County [property]: [read-only] string option PureGym.GymAddress.get_AddressLine1 [method]: unit -> string -PureGym.GymAddress.get_AddressLine2 [method]: unit -> string -PureGym.GymAddress.get_AddressLine3 [method]: unit -> string -PureGym.GymAddress.get_County [method]: unit -> string +PureGym.GymAddress.get_AddressLine2 [method]: unit -> string option +PureGym.GymAddress.get_AddressLine3 [method]: unit -> string option +PureGym.GymAddress.get_County [method]: unit -> string option PureGym.GymAddress.get_Postcode [method]: unit -> string PureGym.GymAddress.get_Town [method]: unit -> string PureGym.GymAddress.Postcode [property]: [read-only] string PureGym.GymAddress.Town [property]: [read-only] string +PureGym.GymAddressModule inherit obj +PureGym.GymAddressModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.GymAddress PureGym.GymAttendance inherit obj, implements PureGym.GymAttendance System.IEquatable, System.Collections.IStructuralEquatable, PureGym.GymAttendance System.IComparable, System.IComparable, System.Collections.IStructuralComparable -PureGym.GymAttendance..ctor [constructor]: (string, int, int, string, bool, System.DateTime, System.DateTime, System.DateTime, int) +PureGym.GymAttendance..ctor [constructor]: (string, int, int, string option, bool, System.DateTime, System.DateTime, System.DateTime, int) PureGym.GymAttendance.AttendanceTime [property]: [read-only] System.DateTime PureGym.GymAttendance.Description [property]: [read-only] string PureGym.GymAttendance.get_AttendanceTime [method]: unit -> System.DateTime @@ -93,26 +97,34 @@ PureGym.GymAttendance.get_LastRefreshedPeopleInClasses [method]: unit -> System. PureGym.GymAttendance.get_MaximumCapacity [method]: unit -> int PureGym.GymAttendance.get_TotalPeopleInClasses [method]: unit -> int PureGym.GymAttendance.get_TotalPeopleInGym [method]: unit -> int -PureGym.GymAttendance.get_TotalPeopleSuffix [method]: unit -> string +PureGym.GymAttendance.get_TotalPeopleSuffix [method]: unit -> string option PureGym.GymAttendance.IsApproximate [property]: [read-only] bool PureGym.GymAttendance.LastRefreshed [property]: [read-only] System.DateTime PureGym.GymAttendance.LastRefreshedPeopleInClasses [property]: [read-only] System.DateTime PureGym.GymAttendance.MaximumCapacity [property]: [read-only] int PureGym.GymAttendance.TotalPeopleInClasses [property]: [read-only] int PureGym.GymAttendance.TotalPeopleInGym [property]: [read-only] int -PureGym.GymAttendance.TotalPeopleSuffix [property]: [read-only] string +PureGym.GymAttendance.TotalPeopleSuffix [property]: [read-only] string option +PureGym.GymAttendanceModule inherit obj +PureGym.GymAttendanceModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.GymAttendance PureGym.GymLocation inherit obj, implements PureGym.GymLocation System.IEquatable, System.Collections.IStructuralEquatable, PureGym.GymLocation System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.GymLocation..ctor [constructor]: (float, float) PureGym.GymLocation.get_Latitude [method]: unit -> float PureGym.GymLocation.get_Longitude [method]: unit -> float PureGym.GymLocation.Latitude [property]: [read-only] float PureGym.GymLocation.Longitude [property]: [read-only] float +PureGym.GymLocationModule inherit obj +PureGym.GymLocationModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.GymLocation +PureGym.GymModule inherit obj +PureGym.GymModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Gym PureGym.GymOpeningHours inherit obj, implements PureGym.GymOpeningHours System.IEquatable, System.Collections.IStructuralEquatable, PureGym.GymOpeningHours System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.GymOpeningHours..ctor [constructor]: (bool, string list) PureGym.GymOpeningHours.get_IsAlwaysOpen [method]: unit -> bool PureGym.GymOpeningHours.get_OpeningHours [method]: unit -> string list PureGym.GymOpeningHours.IsAlwaysOpen [property]: [read-only] bool PureGym.GymOpeningHours.OpeningHours [property]: [read-only] string list +PureGym.GymOpeningHoursModule inherit obj +PureGym.GymOpeningHoursModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.GymOpeningHours PureGym.GymSelector inherit obj, implements PureGym.GymSelector System.IEquatable, System.Collections.IStructuralEquatable, PureGym.GymSelector System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 3 cases PureGym.GymSelector+Id inherit PureGym.GymSelector PureGym.GymSelector+Id.get_Item [method]: unit -> int @@ -143,8 +155,8 @@ PureGym.IPureGymApi.GetGym [method]: int -> PureGym.Gym System.Threading.Tasks.T PureGym.IPureGymApi.GetGymAttendance [method]: int -> PureGym.GymAttendance System.Threading.Tasks.Task PureGym.IPureGymApi.GetGyms [method]: unit -> PureGym.Gym list System.Threading.Tasks.Task PureGym.IPureGymApi.GetMember [method]: unit -> PureGym.Member System.Threading.Tasks.Task -PureGym.IPureGymApi.GetMemberActivity [method]: unit -> PureGym.MemberActivityDto System.Threading.Tasks.Task -PureGym.IPureGymApi.GetSessions [method]: System.DateTime -> System.DateTime -> PureGym.Sessions System.Threading.Tasks.Task +PureGym.IPureGymApi.GetMemberActivity [method]: unit -> string System.Threading.Tasks.Task +PureGym.IPureGymApi.GetSessions [method]: System.DateTime -> System.DateTime -> string System.Threading.Tasks.Task PureGym.Member inherit obj, implements PureGym.Member System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Member System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.Member..ctor [constructor]: (int, string, string, string, int, string, string, string, System.DateOnly, string, string, string, int, int, int) PureGym.Member.CompoundMemberId [property]: [read-only] string @@ -192,6 +204,8 @@ PureGym.MemberActivityDto.ToMemberActivity [method]: unit -> PureGym.MemberActiv PureGym.MemberActivityDto.TotalClasses [property]: [read-only] int PureGym.MemberActivityDto.TotalDuration [property]: [read-only] int PureGym.MemberActivityDto.TotalVisits [property]: [read-only] int +PureGym.MemberActivityDtoModule inherit obj +PureGym.MemberActivityDtoModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.MemberActivityDto PureGym.MemberActivityThisMonth inherit obj, implements PureGym.MemberActivityThisMonth System.IEquatable, System.Collections.IStructuralEquatable, PureGym.MemberActivityThisMonth System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.MemberActivityThisMonth..ctor [constructor]: (int, int, int, int, bool, System.DateTime) PureGym.MemberActivityThisMonth.AverageDurationMinutes [property]: [read-only] int @@ -206,6 +220,8 @@ PureGym.MemberActivityThisMonth.LastRefreshed [property]: [read-only] System.Dat PureGym.MemberActivityThisMonth.TotalClasses [property]: [read-only] int PureGym.MemberActivityThisMonth.TotalDurationMinutes [property]: [read-only] int PureGym.MemberActivityThisMonth.TotalVisits [property]: [read-only] int +PureGym.MemberModule inherit obj +PureGym.MemberModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Member PureGym.Sessions inherit obj, implements PureGym.Sessions System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Sessions System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.Sessions..ctor [constructor]: (PureGym.SessionsSummary, PureGym.Visit list) PureGym.Sessions.get_Summary [method]: unit -> PureGym.SessionsSummary @@ -220,12 +236,18 @@ PureGym.SessionsAggregate.get_Activities [method]: unit -> int PureGym.SessionsAggregate.get_Duration [method]: unit -> int PureGym.SessionsAggregate.get_Visits [method]: unit -> int PureGym.SessionsAggregate.Visits [property]: [read-only] int +PureGym.SessionsAggregateModule inherit obj +PureGym.SessionsAggregateModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.SessionsAggregate +PureGym.SessionsModule inherit obj +PureGym.SessionsModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Sessions PureGym.SessionsSummary inherit obj, implements PureGym.SessionsSummary System.IEquatable, System.Collections.IStructuralEquatable, PureGym.SessionsSummary System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.SessionsSummary..ctor [constructor]: (PureGym.SessionsAggregate, PureGym.SessionsAggregate) PureGym.SessionsSummary.get_ThisWeek [method]: unit -> PureGym.SessionsAggregate PureGym.SessionsSummary.get_Total [method]: unit -> PureGym.SessionsAggregate PureGym.SessionsSummary.ThisWeek [property]: [read-only] PureGym.SessionsAggregate PureGym.SessionsSummary.Total [property]: [read-only] PureGym.SessionsAggregate +PureGym.SessionsSummaryModule inherit obj +PureGym.SessionsSummaryModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.SessionsSummary PureGym.UsernamePin inherit obj, implements PureGym.UsernamePin System.IEquatable, System.Collections.IStructuralEquatable, PureGym.UsernamePin System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.UsernamePin..ctor [constructor]: (string, string) PureGym.UsernamePin.get_Pin [method]: unit -> string @@ -249,4 +271,8 @@ PureGym.VisitGym.get_Name [method]: unit -> string PureGym.VisitGym.get_Status [method]: unit -> string PureGym.VisitGym.Id [property]: [read-only] int PureGym.VisitGym.Name [property]: [read-only] string -PureGym.VisitGym.Status [property]: [read-only] string \ No newline at end of file +PureGym.VisitGym.Status [property]: [read-only] string +PureGym.VisitGymModule inherit obj +PureGym.VisitGymModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.VisitGym +PureGym.VisitModule inherit obj +PureGym.VisitModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Visit \ No newline at end of file diff --git a/PureGym/myriad.toml b/PureGym/myriad.toml new file mode 100644 index 0000000..e69de29 diff --git a/PureGym/version.json b/PureGym/version.json index 958fb13..f3c770d 100644 --- a/PureGym/version.json +++ b/PureGym/version.json @@ -1,5 +1,5 @@ { - "version": "2.0", + "version": "3.0", "publicReleaseRefSpec": [ "^refs/heads/main$" ],