Passed
Push — master ( ab9207...b291d9 )
by Morris
10:44 queued 11s
created

Calendar::getChanges()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 3
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Georg Ehrke <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Roeland Jago Douma <[email protected]>
9
 * @author Thomas Citharel <[email protected]>
10
 * @author Thomas Müller <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
namespace OCA\DAV\CalDAV;
28
29
use OCA\DAV\DAV\Sharing\IShareable;
30
use OCA\DAV\Exception\UnsupportedLimitOnInitialSyncException;
31
use OCP\IConfig;
32
use OCP\IL10N;
33
use Sabre\CalDAV\Backend\BackendInterface;
34
use Sabre\DAV\Exception\Forbidden;
35
use Sabre\DAV\Exception\NotFound;
36
use Sabre\DAV\PropPatch;
37
38
/**
39
 * Class Calendar
40
 *
41
 * @package OCA\DAV\CalDAV
42
 * @property BackendInterface|CalDavBackend $caldavBackend
43
 */
44
class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
45
46
	/** @var IConfig */
47
	private $config;
48
49
	public function __construct(BackendInterface $caldavBackend, $calendarInfo, IL10N $l10n, IConfig $config) {
50
		parent::__construct($caldavBackend, $calendarInfo);
51
52
		if ($this->getName() === BirthdayService::BIRTHDAY_CALENDAR_URI) {
53
			$this->calendarInfo['{DAV:}displayname'] = $l10n->t('Contact birthdays');
54
		}
55
		if ($this->getName() === CalDavBackend::PERSONAL_CALENDAR_URI &&
56
			$this->calendarInfo['{DAV:}displayname'] === CalDavBackend::PERSONAL_CALENDAR_NAME) {
57
			$this->calendarInfo['{DAV:}displayname'] = $l10n->t('Personal');
58
		}
59
60
		$this->config = $config;
61
	}
62
63
	/**
64
	 * Updates the list of shares.
65
	 *
66
	 * The first array is a list of people that are to be added to the
67
	 * resource.
68
	 *
69
	 * Every element in the add array has the following properties:
70
	 *   * href - A url. Usually a mailto: address
71
	 *   * commonName - Usually a first and last name, or false
72
	 *   * summary - A description of the share, can also be false
73
	 *   * readOnly - A boolean value
74
	 *
75
	 * Every element in the remove array is just the address string.
76
	 *
77
	 * @param array $add
78
	 * @param array $remove
79
	 * @return void
80
	 * @throws Forbidden
81
	 */
82
	public function updateShares(array $add, array $remove) {
83
		if ($this->isShared()) {
84
			throw new Forbidden();
85
		}
86
		$this->caldavBackend->updateShares($this, $add, $remove);
0 ignored issues
show
Bug introduced by
The method updateShares() does not exist on Sabre\CalDAV\Backend\BackendInterface. It seems like you code against a sub-type of Sabre\CalDAV\Backend\BackendInterface such as OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

86
		$this->caldavBackend->/** @scrutinizer ignore-call */ 
87
                        updateShares($this, $add, $remove);
Loading history...
87
	}
88
89
	/**
90
	 * Returns the list of people whom this resource is shared with.
91
	 *
92
	 * Every element in this array should have the following properties:
93
	 *   * href - Often a mailto: address
94
	 *   * commonName - Optional, for example a first + last name
95
	 *   * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
96
	 *   * readOnly - boolean
97
	 *   * summary - Optional, a description for the share
98
	 *
99
	 * @return array
100
	 */
101
	public function getShares() {
102
		if ($this->isShared()) {
103
			return [];
104
		}
105
		return $this->caldavBackend->getShares($this->getResourceId());
0 ignored issues
show
Bug introduced by
The method getShares() does not exist on Sabre\CalDAV\Backend\BackendInterface. It seems like you code against a sub-type of Sabre\CalDAV\Backend\BackendInterface such as OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

105
		return $this->caldavBackend->/** @scrutinizer ignore-call */ getShares($this->getResourceId());
Loading history...
106
	}
107
108
	/**
109
	 * @return int
110
	 */
111
	public function getResourceId() {
112
		return $this->calendarInfo['id'];
113
	}
114
115
	/**
116
	 * @return string
117
	 */
118
	public function getPrincipalURI() {
119
		return $this->calendarInfo['principaluri'];
120
	}
121
122
	public function getACL() {
123
		$acl =  [
124
			[
125
				'privilege' => '{DAV:}read',
126
				'principal' => $this->getOwner(),
127
				'protected' => true,
128
			]];
129
		if ($this->getName() !== BirthdayService::BIRTHDAY_CALENDAR_URI) {
130
			$acl[] = [
131
				'privilege' => '{DAV:}write',
132
				'principal' => $this->getOwner(),
133
				'protected' => true,
134
			];
135
		} else {
136
			$acl[] = [
137
				'privilege' => '{DAV:}write-properties',
138
				'principal' => $this->getOwner(),
139
				'protected' => true,
140
			];
141
		}
142
143
		if (!$this->isShared()) {
144
			return $acl;
145
		}
146
147
		if ($this->getOwner() !== parent::getOwner()) {
148
			$acl[] =  [
149
					'privilege' => '{DAV:}read',
150
					'principal' => parent::getOwner(),
151
					'protected' => true,
152
				];
153
			if ($this->canWrite()) {
154
				$acl[] = [
155
					'privilege' => '{DAV:}write',
156
					'principal' => parent::getOwner(),
157
					'protected' => true,
158
				];
159
			} else {
160
				$acl[] = [
161
					'privilege' => '{DAV:}write-properties',
162
					'principal' => parent::getOwner(),
163
					'protected' => true,
164
				];
165
			}
166
		}
167
		if ($this->isPublic()) {
168
			$acl[] = [
169
				'privilege' => '{DAV:}read',
170
				'principal' => 'principals/system/public',
171
				'protected' => true,
172
			];
173
		}
174
175
		$acl = $this->caldavBackend->applyShareAcl($this->getResourceId(), $acl);
0 ignored issues
show
Bug introduced by
The method applyShareAcl() does not exist on Sabre\CalDAV\Backend\BackendInterface. It seems like you code against a sub-type of Sabre\CalDAV\Backend\BackendInterface such as OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

175
		/** @scrutinizer ignore-call */ 
176
  $acl = $this->caldavBackend->applyShareAcl($this->getResourceId(), $acl);
Loading history...
176
		$allowedPrincipals = [$this->getOwner(), parent::getOwner(), 'principals/system/public'];
177
		return array_filter($acl, function($rule) use ($allowedPrincipals) {
178
			return \in_array($rule['principal'], $allowedPrincipals, true);
179
		});
180
	}
181
182
	public function getChildACL() {
183
		return $this->getACL();
184
	}
185
186
	public function getOwner() {
187
		if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) {
188
			return $this->calendarInfo['{http://owncloud.org/ns}owner-principal'];
189
		}
190
		return parent::getOwner();
191
	}
192
193
	public function delete() {
194
		if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal']) &&
195
			$this->calendarInfo['{http://owncloud.org/ns}owner-principal'] !== $this->calendarInfo['principaluri']) {
196
			$principal = 'principal:' . parent::getOwner();
197
			$shares = $this->caldavBackend->getShares($this->getResourceId());
198
			$shares = array_filter($shares, function($share) use ($principal){
199
				return $share['href'] === $principal;
200
			});
201
			if (empty($shares)) {
202
				throw new Forbidden();
203
			}
204
205
			$this->caldavBackend->updateShares($this, [], [
206
				$principal
207
			]);
208
			return;
209
		}
210
211
		// Remember when a user deleted their birthday calendar
212
		// in order to not regenerate it on the next contacts change
213
		if ($this->getName() === BirthdayService::BIRTHDAY_CALENDAR_URI) {
214
			$principalURI = $this->getPrincipalURI();
215
			$userId = substr($principalURI, 17);
216
217
			$this->config->setUserValue($userId, 'dav', 'generateBirthdayCalendar', 'no');
218
		}
219
220
		parent::delete();
221
	}
222
223
	public function propPatch(PropPatch $propPatch) {
224
		// parent::propPatch will only update calendars table
225
		// if calendar is shared, changes have to be made to the properties table
226
		if (!$this->isShared()) {
227
			parent::propPatch($propPatch);
228
		}
229
	}
230
231
	public function getChild($name) {
232
233
		$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name);
234
235
		if (!$obj) {
236
			throw new NotFound('Calendar object not found');
237
		}
238
239
		if ($obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE && $this->isShared()) {
240
			throw new NotFound('Calendar object not found');
241
		}
242
243
		$obj['acl'] = $this->getChildACL();
244
245
		return new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
246
247
	}
248
249
	public function getChildren() {
250
251
		$objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id']);
252
		$children = [];
253
		foreach ($objs as $obj) {
254
			if ($obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE && $this->isShared()) {
255
				continue;
256
			}
257
			$obj['acl'] = $this->getChildACL();
258
			$children[] = new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
259
		}
260
		return $children;
261
262
	}
263
264
	public function getMultipleChildren(array $paths) {
265
266
		$objs = $this->caldavBackend->getMultipleCalendarObjects($this->calendarInfo['id'], $paths);
267
		$children = [];
268
		foreach ($objs as $obj) {
269
			if ($obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE && $this->isShared()) {
270
				continue;
271
			}
272
			$obj['acl'] = $this->getChildACL();
273
			$children[] = new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
274
		}
275
		return $children;
276
277
	}
278
279
	public function childExists($name) {
280
		$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name);
281
		if (!$obj) {
282
			return false;
283
		}
284
		if ($obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE && $this->isShared()) {
285
			return false;
286
		}
287
288
		return true;
289
	}
290
291
	public function calendarQuery(array $filters) {
292
293
		$uris = $this->caldavBackend->calendarQuery($this->calendarInfo['id'], $filters);
294
		if ($this->isShared()) {
295
			return array_filter($uris, function ($uri) {
296
				return $this->childExists($uri);
297
			});
298
		}
299
300
		return $uris;
301
	}
302
303
	/**
304
	 * @param boolean $value
305
	 * @return string|null
306
	 */
307
	public function setPublishStatus($value) {
308
		$publicUri = $this->caldavBackend->setPublishStatus($value, $this);
0 ignored issues
show
Bug introduced by
The method setPublishStatus() does not exist on Sabre\CalDAV\Backend\BackendInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Sabre\CalDAV\Backend\SubscriptionSupport or Sabre\CalDAV\Backend\SchedulingSupport or Sabre\CalDAV\Backend\SyncSupport or Sabre\CalDAV\Backend\AbstractBackend or Sabre\CalDAV\Backend\NotificationSupport or Sabre\CalDAV\Backend\SimplePDO. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

308
		/** @scrutinizer ignore-call */ 
309
  $publicUri = $this->caldavBackend->setPublishStatus($value, $this);
Loading history...
309
		$this->calendarInfo['publicuri'] = $publicUri;
310
		return $publicUri;
311
	}
312
313
	/**
314
	 * @return mixed $value
315
	 */
316
	public function getPublishStatus() {
317
		return $this->caldavBackend->getPublishStatus($this);
0 ignored issues
show
Bug introduced by
The method getPublishStatus() does not exist on Sabre\CalDAV\Backend\BackendInterface. It seems like you code against a sub-type of Sabre\CalDAV\Backend\BackendInterface such as OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend or OCA\DAV\CalDAV\CalDavBackend. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

317
		return $this->caldavBackend->/** @scrutinizer ignore-call */ getPublishStatus($this);
Loading history...
318
	}
319
320
	private function canWrite() {
321
		if (isset($this->calendarInfo['{http://owncloud.org/ns}read-only'])) {
322
			return !$this->calendarInfo['{http://owncloud.org/ns}read-only'];
323
		}
324
		return true;
325
	}
326
327
	private function isPublic() {
328
		return isset($this->calendarInfo['{http://owncloud.org/ns}public']);
329
	}
330
331
	protected function isShared() {
332
		if (!isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) {
333
			return false;
334
		}
335
336
		return $this->calendarInfo['{http://owncloud.org/ns}owner-principal'] !== $this->calendarInfo['principaluri'];
337
	}
338
339
	public function isSubscription() {
340
		return isset($this->calendarInfo['{http://calendarserver.org/ns/}source']);
341
	}
342
343
	/**
344
	 * @inheritDoc
345
	 */
346
	public function getChanges($syncToken, $syncLevel, $limit = null) {
347
		if (!$syncToken && $limit) {
348
			throw new UnsupportedLimitOnInitialSyncException();
349
		}
350
351
		return parent::getChanges($syncToken, $syncLevel, $limit);
352
	}
353
}
354