1
|
|
|
<?php namespace CalDAVClient\Facade; |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Copyright 2017 OpenStack Foundation |
5
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
6
|
|
|
* you may not use this file except in compliance with the License. |
7
|
|
|
* You may obtain a copy of the License at |
8
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0 |
9
|
|
|
* Unless required by applicable law or agreed to in writing, software |
10
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
11
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12
|
|
|
* See the License for the specific language governing permissions and |
13
|
|
|
* limitations under the License. |
14
|
|
|
**/ |
15
|
|
|
|
16
|
|
|
use CalDAVClient\Facade\Exceptions\ForbiddenException; |
17
|
|
|
use CalDAVClient\Facade\Requests\CalDAVRequestFactory; |
18
|
|
|
use CalDAVClient\Facade\Requests\CalendarQueryFilter; |
19
|
|
|
use CalDAVClient\Facade\Requests\EventRequestVO; |
20
|
|
|
use CalDAVClient\Facade\Requests\MakeCalendarRequestVO; |
21
|
|
|
use CalDAVClient\Facade\Responses\CalendarDeletedResponse; |
22
|
|
|
use CalDAVClient\Facade\Responses\CalendarHomesResponse; |
23
|
|
|
use CalDAVClient\Facade\Responses\CalendarSyncInfoResponse; |
24
|
|
|
use CalDAVClient\Facade\Responses\EventCreatedResponse; |
25
|
|
|
use CalDAVClient\Facade\Responses\EventDeletedResponse; |
26
|
|
|
use CalDAVClient\Facade\Responses\EventUpdatedResponse; |
27
|
|
|
use CalDAVClient\Facade\Responses\GetCalendarResponse; |
28
|
|
|
use CalDAVClient\Facade\Responses\GetCalendarsResponse; |
29
|
|
|
use CalDAVClient\Facade\Responses\ResourceCollectionResponse; |
30
|
|
|
use CalDAVClient\Facade\Responses\UserPrincipalResponse; |
31
|
|
|
use CalDAVClient\Facade\Utils\RequestFactory; |
32
|
|
|
use CalDAVClient\ICalDavClient; |
33
|
|
|
use CalDAVClient\Facade\Exceptions\NotFoundResourceException; |
34
|
|
|
use CalDAVClient\Facade\Exceptions\ServerErrorException; |
35
|
|
|
use CalDAVClient\Facade\Exceptions\UserUnAuthorizedException; |
36
|
|
|
use GuzzleHttp\Client; |
37
|
|
|
use GuzzleHttp\Exception\ClientException; |
38
|
|
|
use GuzzleHttp\Psr7\Request; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Class CalDavClient |
42
|
|
|
* @package CalDAVClient\Facade |
43
|
|
|
*/ |
44
|
|
|
final class CalDavClient implements ICalDavClient |
45
|
|
|
{ |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* As indicated in Section 3.10 of [RFC2445], the URL of calendar object |
49
|
|
|
* resources containing (an arbitrary set of) calendaring and scheduling |
50
|
|
|
* information may be suffixed by ".ics", and the URL of calendar object |
51
|
|
|
* resources containing free or busy time information may be suffixed by |
52
|
|
|
* ".ifb". |
53
|
|
|
*/ |
54
|
|
|
|
55
|
|
|
const SchedulingInformationSuffix = '.ics'; |
56
|
|
|
|
57
|
|
|
const FreeBusyTimeInformationSuffix = '.ics'; |
58
|
|
|
|
59
|
|
|
const ETagHeader = 'ETag'; |
60
|
|
|
|
61
|
|
|
const DAVHeader = 'DAV'; |
62
|
|
|
|
63
|
|
|
const CalendarAccessOption = 'calendar-access'; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var string |
67
|
|
|
*/ |
68
|
|
|
private $server_url; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @var string |
72
|
|
|
*/ |
73
|
|
|
private $user; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @var string |
77
|
|
|
*/ |
78
|
|
|
private $password; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @var Client |
82
|
|
|
*/ |
83
|
|
|
private $client; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @var int |
87
|
|
|
*/ |
88
|
|
|
private $timeout = 60; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* CalDavClient constructor. |
92
|
|
|
* @param string $server_url |
93
|
|
|
* @param string|null $user |
94
|
|
|
* @param string|null $password |
95
|
|
|
*/ |
96
|
|
|
public function __construct($server_url, $user = null, $password = null) |
97
|
|
|
{ |
98
|
|
|
$this->server_url = $server_url; |
99
|
|
|
$this->user = $user; |
100
|
|
|
$this->password = $password; |
101
|
|
|
$this->client = new Client(); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* @param string $server_url |
106
|
|
|
* @return void |
107
|
|
|
*/ |
108
|
|
|
public function setServerUrl($server_url) |
109
|
|
|
{ |
110
|
|
|
$this->server_url = $server_url; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* @param string $username |
115
|
|
|
* @param string $password |
116
|
|
|
* @return void |
117
|
|
|
*/ |
118
|
|
|
public function setCredentials($username, $password) |
119
|
|
|
{ |
120
|
|
|
$this->user = $username; |
121
|
|
|
$this->password = $password; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* @param Request $http_request |
126
|
|
|
* @return mixed|\Psr\Http\Message\ResponseInterface |
127
|
|
|
*/ |
128
|
|
|
private function makeRequest(Request $http_request){ |
129
|
|
|
try{ |
130
|
|
|
return $this->client->send($http_request, [ |
131
|
|
|
'auth' => [$this->user, $this->password], |
132
|
|
|
'timeout' => $this->timeout |
133
|
|
|
]); |
134
|
|
|
} |
135
|
|
|
catch (ClientException $ex){ |
136
|
|
|
switch($ex->getCode()){ |
137
|
|
|
case 401: |
138
|
|
|
throw new UserUnAuthorizedException(); |
139
|
|
|
break; |
140
|
|
|
case 404: |
141
|
|
|
throw new NotFoundResourceException(); |
142
|
|
|
break; |
143
|
|
|
case 403: |
144
|
|
|
throw new ForbiddenException(); |
145
|
|
|
default: |
146
|
|
|
throw new ServerErrorException(); |
147
|
|
|
break; |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* @return bool |
154
|
|
|
*/ |
155
|
|
|
public function isValidServer() |
156
|
|
|
{ |
157
|
|
|
|
158
|
|
|
$http_response = $this->makeRequest( |
159
|
|
|
RequestFactory::createOptionsRequest($this->server_url) |
160
|
|
|
); |
161
|
|
|
|
162
|
|
|
$res = $http_response->hasHeader(self::DAVHeader); |
163
|
|
|
$options = []; |
164
|
|
|
if($res){ |
165
|
|
|
$val = $http_response->getHeaderLine(self::DAVHeader); |
166
|
|
|
if(!empty($val)){ |
167
|
|
|
$options = explode(', ', $val); |
168
|
|
|
} |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
return $res && count($options) > 0 && in_array(self::CalendarAccessOption, $options); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* @return UserPrincipalResponse |
176
|
|
|
*/ |
177
|
|
View Code Duplication |
public function getUserPrincipal() |
|
|
|
|
178
|
|
|
{ |
179
|
|
|
$http_response = $this->makeRequest( |
180
|
|
|
RequestFactory::createPropFindRequest |
181
|
|
|
( |
182
|
|
|
$this->server_url, |
183
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::PrincipalRequestType)->getContent() |
184
|
|
|
) |
185
|
|
|
); |
186
|
|
|
|
187
|
|
|
return new UserPrincipalResponse($this->server_url, (string)$http_response->getBody(), $http_response->getStatusCode()); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* @param string $principal_url |
192
|
|
|
* @return CalendarHomesResponse |
193
|
|
|
*/ |
194
|
|
View Code Duplication |
public function getCalendarHome($principal_url) |
|
|
|
|
195
|
|
|
{ |
196
|
|
|
$http_response = $this->makeRequest( |
197
|
|
|
RequestFactory::createPropFindRequest |
198
|
|
|
( |
199
|
|
|
$principal_url, |
200
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::CalendarHomeRequestType)->getContent() |
201
|
|
|
) |
202
|
|
|
); |
203
|
|
|
|
204
|
|
|
return new CalendarHomesResponse($this->server_url, (string)$http_response->getBody(), $http_response->getStatusCode()); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* @param string $calendar_home_set |
209
|
|
|
* @param MakeCalendarRequestVO $vo |
210
|
|
|
* @see https://tools.ietf.org/html/rfc4791#section-5.3.1 |
211
|
|
|
* @return string|boolean |
212
|
|
|
*/ |
213
|
|
|
public function createCalendar($calendar_home_set, MakeCalendarRequestVO $vo) |
214
|
|
|
{ |
215
|
|
|
$http_response = $this->makeRequest( |
216
|
|
|
RequestFactory::createMakeCalendarRequest |
217
|
|
|
( |
218
|
|
|
$calendar_home_set.$vo->getResourceName(), |
219
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::CalendarCreateRequestType, [$vo])->getContent() |
220
|
|
|
) |
221
|
|
|
); |
222
|
|
|
|
223
|
|
|
return $http_response->getStatusCode() == 201 ? $calendar_home_set.$vo->getResourceName() : false; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* @param string $calendar_home_set_url |
228
|
|
|
* @return GetCalendarsResponse |
229
|
|
|
*/ |
230
|
|
View Code Duplication |
public function getCalendars($calendar_home_set_url) |
|
|
|
|
231
|
|
|
{ |
232
|
|
|
$http_response = $this->makeRequest( |
233
|
|
|
RequestFactory::createPropFindRequest |
234
|
|
|
( |
235
|
|
|
$calendar_home_set_url, |
236
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::CalendarsRequestType)->getContent() |
237
|
|
|
) |
238
|
|
|
); |
239
|
|
|
|
240
|
|
|
return new GetCalendarsResponse($this->server_url, (string)$http_response->getBody(), $http_response->getStatusCode()); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* @param string $calendar_url |
245
|
|
|
* @return GetCalendarResponse |
246
|
|
|
*/ |
247
|
|
View Code Duplication |
public function getCalendar($calendar_url) |
|
|
|
|
248
|
|
|
{ |
249
|
|
|
$http_response = $this->makeRequest( |
250
|
|
|
RequestFactory::createPropFindRequest |
251
|
|
|
( |
252
|
|
|
$calendar_url, |
253
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::CalendarRequestType)->getContent(), |
254
|
|
|
0 |
255
|
|
|
) |
256
|
|
|
); |
257
|
|
|
|
258
|
|
|
return new GetCalendarResponse($this->server_url, (string)$http_response->getBody(), $http_response->getStatusCode()); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* @param string $calendar_url |
264
|
|
|
* @param string $sync_token |
265
|
|
|
* @return CalendarSyncInfoResponse |
266
|
|
|
*/ |
267
|
|
View Code Duplication |
public function getCalendarSyncInfo($calendar_url, $sync_token) |
|
|
|
|
268
|
|
|
{ |
269
|
|
|
|
270
|
|
|
$http_response = $this->makeRequest( |
271
|
|
|
RequestFactory::createReportRequest |
272
|
|
|
( |
273
|
|
|
$calendar_url, |
274
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::CalendarSyncRequestType, [$sync_token])->getContent() |
275
|
|
|
) |
276
|
|
|
); |
277
|
|
|
|
278
|
|
|
return new CalendarSyncInfoResponse($this->server_url, (string)$http_response->getBody(), $http_response->getStatusCode()); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* @param string $calendar_url |
283
|
|
|
* @param EventRequestVO $vo |
284
|
|
|
* @return EventCreatedResponse |
285
|
|
|
*/ |
286
|
|
View Code Duplication |
public function createEvent($calendar_url, EventRequestVO $vo) |
|
|
|
|
287
|
|
|
{ |
288
|
|
|
$uid = $vo->getUID(); |
289
|
|
|
$resource_url = $calendar_url.$uid.self::SchedulingInformationSuffix; |
290
|
|
|
$http_response = $this->makeRequest( |
291
|
|
|
RequestFactory::createPutRequest |
292
|
|
|
( |
293
|
|
|
$resource_url, |
294
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::EventCreateRequestType, [$vo])->getContent() |
295
|
|
|
) |
296
|
|
|
); |
297
|
|
|
$etag = $http_response->hasHeader(self::ETagHeader) ? $http_response->getHeaderLine(self::ETagHeader) : null; |
298
|
|
|
return new EventCreatedResponse |
299
|
|
|
( |
300
|
|
|
$uid, |
301
|
|
|
$etag, |
302
|
|
|
$resource_url, |
303
|
|
|
(string)$http_response->getBody(), |
304
|
|
|
$http_response->getStatusCode() |
305
|
|
|
); |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* @param string $calendar_url |
310
|
|
|
* @param EventRequestVO $vo |
311
|
|
|
* @param string $etag |
312
|
|
|
* @return EventUpdatedResponse |
313
|
|
|
*/ |
314
|
|
View Code Duplication |
public function updateEvent($calendar_url, EventRequestVO $vo, $etag) |
|
|
|
|
315
|
|
|
{ |
316
|
|
|
$uid = $vo->getUID(); |
317
|
|
|
$resource_url = $calendar_url.$uid.self::SchedulingInformationSuffix; |
318
|
|
|
$http_response = $this->makeRequest( |
319
|
|
|
RequestFactory::createPutRequest |
320
|
|
|
( |
321
|
|
|
$resource_url, |
322
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::EventUpdateRequestType, [$vo])->getContent(), |
323
|
|
|
$etag |
324
|
|
|
) |
325
|
|
|
); |
326
|
|
|
$etag = $http_response->hasHeader(self::ETagHeader) ? $http_response->getHeaderLine(self::ETagHeader) : null; |
327
|
|
|
return new EventUpdatedResponse |
328
|
|
|
( |
329
|
|
|
$uid, |
330
|
|
|
$etag, |
331
|
|
|
$resource_url, |
332
|
|
|
(string)$http_response->getBody(), |
333
|
|
|
$http_response->getStatusCode() |
334
|
|
|
); |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* @param string $calendar_url |
339
|
|
|
* @param string $uid |
340
|
|
|
* @param string $etag |
341
|
|
|
* @return EventDeletedResponse |
342
|
|
|
*/ |
343
|
|
View Code Duplication |
public function deleteEvent($calendar_url, $uid, $etag) |
|
|
|
|
344
|
|
|
{ |
345
|
|
|
$http_response = $this->makeRequest( |
346
|
|
|
RequestFactory::createDeleteRequest |
347
|
|
|
( |
348
|
|
|
$calendar_url.$uid.self::SchedulingInformationSuffix, |
349
|
|
|
$etag |
350
|
|
|
) |
351
|
|
|
); |
352
|
|
|
|
353
|
|
|
return new EventDeletedResponse |
354
|
|
|
( |
355
|
|
|
$this->server_url, (string)$http_response->getBody(), $http_response->getStatusCode() |
|
|
|
|
356
|
|
|
); |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* @param string $event_url |
361
|
|
|
* @return string |
362
|
|
|
*/ |
363
|
|
|
public function getEventVCardBy($event_url){ |
364
|
|
|
$http_response = $this->makeRequest( |
365
|
|
|
RequestFactory::createGetRequest |
366
|
|
|
( |
367
|
|
|
$event_url |
368
|
|
|
) |
369
|
|
|
); |
370
|
|
|
|
371
|
|
|
$ical = (string)$http_response->getBody(); |
372
|
|
|
return $ical; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
/** |
376
|
|
|
* @param string $calendar_url |
377
|
|
|
* @param array $events_urls |
378
|
|
|
* @return ResourceCollectionResponse |
379
|
|
|
*/ |
380
|
|
View Code Duplication |
public function getEventsBy($calendar_url, array $events_urls) |
|
|
|
|
381
|
|
|
{ |
382
|
|
|
$http_response = $this->makeRequest( |
383
|
|
|
RequestFactory::createReportRequest |
384
|
|
|
( |
385
|
|
|
$calendar_url, |
386
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::CalendarMultiGetRequestType, [$events_urls])->getContent() |
387
|
|
|
) |
388
|
|
|
); |
389
|
|
|
|
390
|
|
|
return new ResourceCollectionResponse |
391
|
|
|
( |
392
|
|
|
$this->server_url, |
393
|
|
|
(string)$http_response->getBody(), |
394
|
|
|
$http_response->getStatusCode() |
395
|
|
|
); |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
/** |
399
|
|
|
* @param string $calendar_url |
400
|
|
|
* @param CalendarQueryFilter $filter |
401
|
|
|
* @return ResourceCollectionResponse |
402
|
|
|
*/ |
403
|
|
View Code Duplication |
public function getEventsByQuery($calendar_url, CalendarQueryFilter $filter) |
|
|
|
|
404
|
|
|
{ |
405
|
|
|
|
406
|
|
|
$http_response = $this->makeRequest( |
407
|
|
|
RequestFactory::createReportRequest |
408
|
|
|
( |
409
|
|
|
$calendar_url, |
410
|
|
|
CalDAVRequestFactory::getInstance()->build(CalDAVRequestFactory::CalendarQueryRequestType, [$filter])->getContent() |
411
|
|
|
) |
412
|
|
|
); |
413
|
|
|
|
414
|
|
|
return new ResourceCollectionResponse |
415
|
|
|
( |
416
|
|
|
$this->server_url, |
417
|
|
|
(string)$http_response->getBody(), |
418
|
|
|
$http_response->getStatusCode() |
419
|
|
|
); |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
/** |
423
|
|
|
* @param string $calendar_url |
424
|
|
|
* @param string|null $etag |
425
|
|
|
* @return CalendarDeletedResponse |
426
|
|
|
*/ |
427
|
|
View Code Duplication |
public function deleteCalendar($calendar_url, $etag = null) |
|
|
|
|
428
|
|
|
{ |
429
|
|
|
$http_response = $this->makeRequest( |
430
|
|
|
RequestFactory::createDeleteRequest |
431
|
|
|
( |
432
|
|
|
$calendar_url, |
433
|
|
|
$etag |
434
|
|
|
) |
435
|
|
|
); |
436
|
|
|
|
437
|
|
|
return new CalendarDeletedResponse |
438
|
|
|
( |
439
|
|
|
$this->server_url, (string)$http_response->getBody(), $http_response->getStatusCode() |
|
|
|
|
440
|
|
|
); |
441
|
|
|
} |
442
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.