-
Notifications
You must be signed in to change notification settings - Fork 0
/
GotCourts.fs
158 lines (123 loc) · 5.38 KB
/
GotCourts.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
namespace TcFairplay
open System
open System.Collections.Generic
open System.Net.Http
open System.Text.Json
type AuthData = {
ApiKey: string
PhpSessionId: string
}
type GotCourtsError = string
module GotCourts =
let private baseUrl = "https://apps.gotcourts.com"
let private blockingUrl = baseUrl + "/de/api2/secured/club/blocking"
// blockings path: /response/blockings/[]
// path contains object with id, courtId, startTime, endTime, shortDesc, type, note.
let private listUrlTemplate = baseUrl + "/de/api/secured/club/reservation/list?clubId={0}&date={1}"
let private apiKeyHeader = "X-GOTCOURTS", "ApiKey=\"{0}\""
let private cookieHeader = "Cookie", "PHPSESSID={0}"
let createClient (auth: AuthData): HttpClient =
let client = new HttpClient()
let add (name, format) (value: string) =
client.DefaultRequestHeaders.Add (name, String.Format(format, value))
add apiKeyHeader auth.ApiKey
add cookieHeader auth.PhpSessionId
client
module private Api =
let private dateFormat = "yyyy-MM-dd"
let formatDate (date: DateOnly): string =
date.ToString(dateFormat)
let parseDate (s: string): DateOnly =
DateOnly.ParseExact(s, dateFormat)
let formatTime (time: TimeOnly): string =
(time.Hour * 60 + time.Minute) * 60
|> string
let calcTime (secondsSinceMidnight: int): TimeOnly =
TimeOnly(int64 secondsSinceMidnight * 10_000_000L)
let private toKeyValuePair (x, y) = KeyValuePair(x, y)
let private clubId = 53223
let private courtToId = function
| Court1 -> 8153
| Court2 -> 8154
| Court3 -> 8155
let private idToCourt = function
| 8153 -> Court1
| 8154 -> Court2
| 8155 -> Court3
| id -> failwithf "Unknown court id '%d." id
let private buildBlockingPairs (blocking: Blocking): (string * string) list =
let toCourtPair no = ("courts[]", no |> courtToId |> string)
let dateTimePairs =
let timePairs =
match blocking.StartEnd with
| Some (s, e) -> [
"time[start]", Api.formatTime s
"time[end]", Api.formatTime e
]
| None -> []
let date = Api.formatDate blocking.Date
[
"date", date
"dateTo", date
"allDay[disabled]", (blocking.StartEnd |> Option.isSome |> string |> fun s -> s.ToLower())
] @ timePairs
dateTimePairs @
(blocking.Courts |> List.map toCourtPair) @
[
"autoremove", "true"
"type", "other"
"description", blocking.Description
"note", blocking.Note
]
let processResponse (rawJson: string): Result<JsonElement, GotCourtsError> =
let doc = JsonDocument.Parse rawJson
let success = (doc.RootElement.GetProperty "status").GetBoolean()
let resp = doc.RootElement.GetProperty "response"
if success then
Ok resp
else
let errorText = (resp.GetProperty "error").GetString()
Error errorText
let createBlocking (client: HttpClient) (blocking: Blocking): Result<Guid list, GotCourtsError> =
let pairs = buildBlockingPairs blocking
use content = new FormUrlEncodedContent(pairs |> List.map toKeyValuePair)
let respMsg = client.PostAsync (blockingUrl, content) |> await
let rawJson = respMsg.Content.ReadAsStringAsync() |> await
let getIds (resp: JsonElement) =
let ids = resp.GetProperty "ids"
ids.EnumerateArray()
|> Seq.map (fun id -> Guid.Parse (id.GetString()))
|> Seq.toList
processResponse rawJson
|> Result.map getIds
let deleteBlocking (client: HttpClient) (id: Guid): Result<unit, string> =
let url = String.Format("{0}/{1}", blockingUrl, id)
use reqMsg = new HttpRequestMessage (HttpMethod.Delete, url)
use respMsg = client.Send(reqMsg)
respMsg.Content.ReadAsStringAsync() |> await
|> processResponse
|> Result.map ignore
let loadBlockings (client: HttpClient) (date: DateOnly): Result<(Guid * Blocking) list, GotCourtsError> =
let url = String.Format(listUrlTemplate, clubId, Api.formatDate date)
let rawJson = client.GetStringAsync(url) |> await
let getBlockings (resp: JsonElement) =
let blockings = resp.GetProperty "blockings"
let parseBlocking (el: JsonElement): (Guid * Blocking) =
let get (name: string) = el.GetProperty name
let getString name = (get name).GetString()
let getInt name = (get name).GetInt32()
let getTime = getInt >> Api.calcTime
let guid = Guid.Parse (getString "id")
let blocking = {
Description = (getString "shortDesc")
Courts = [getInt "courtId" |> idToCourt]
Date = date
StartEnd = Some (getTime "startTime", getTime "endTime")
Note = getString "note"
}
(guid, blocking)
blockings.EnumerateArray ()
|> Seq.map parseBlocking
|> Seq.toList
processResponse rawJson
|> Result.map getBlockings