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

AddressBook::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 Joas Schilling <[email protected]>
6
 * @author Thomas Müller <[email protected]>
7
 *
8
 * @license AGPL-3.0
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
namespace OCA\DAV\CardDAV;
24
25
use OCA\DAV\DAV\Sharing\IShareable;
26
use OCA\DAV\Exception\UnsupportedLimitOnInitialSyncException;
27
use OCP\IL10N;
28
use Sabre\CardDAV\Backend\BackendInterface;
29
use Sabre\CardDAV\Card;
30
use Sabre\DAV\Exception\Forbidden;
31
use Sabre\DAV\Exception\NotFound;
32
use Sabre\DAV\PropPatch;
33
34
/**
35
 * Class AddressBook
36
 *
37
 * @package OCA\DAV\CardDAV
38
 * @property BackendInterface|CardDavBackend $carddavBackend
39
 */
40
class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
41
42
	/**
43
	 * AddressBook constructor.
44
	 *
45
	 * @param BackendInterface $carddavBackend
46
	 * @param array $addressBookInfo
47
	 * @param IL10N $l10n
48
	 */
49
	public function __construct(BackendInterface $carddavBackend, array $addressBookInfo, IL10N $l10n) {
50
		parent::__construct($carddavBackend, $addressBookInfo);
51
52
		if ($this->addressBookInfo['{DAV:}displayname'] === CardDavBackend::PERSONAL_ADDRESSBOOK_NAME &&
53
			$this->getName() === CardDavBackend::PERSONAL_ADDRESSBOOK_URI) {
54
			$this->addressBookInfo['{DAV:}displayname'] = $l10n->t('Contacts');
55
		}
56
	}
57
58
	/**
59
	 * Updates the list of shares.
60
	 *
61
	 * The first array is a list of people that are to be added to the
62
	 * addressbook.
63
	 *
64
	 * Every element in the add array has the following properties:
65
	 *   * href - A url. Usually a mailto: address
66
	 *   * commonName - Usually a first and last name, or false
67
	 *   * summary - A description of the share, can also be false
68
	 *   * readOnly - A boolean value
69
	 *
70
	 * Every element in the remove array is just the address string.
71
	 *
72
	 * @param array $add
73
	 * @param array $remove
74
	 * @return void
75
	 * @throws Forbidden
76
	 */
77
	public function updateShares(array $add, array $remove) {
78
		if ($this->isShared()) {
79
			throw new Forbidden();
80
		}
81
		$this->carddavBackend->updateShares($this, $add, $remove);
0 ignored issues
show
Bug introduced by
The method updateShares() does not exist on Sabre\CardDAV\Backend\BackendInterface. Did you maybe mean updateCard()? ( Ignorable by Annotation )

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

81
		$this->carddavBackend->/** @scrutinizer ignore-call */ 
82
                         updateShares($this, $add, $remove);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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

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

100
		return $this->carddavBackend->/** @scrutinizer ignore-call */ getShares($this->getResourceId());
Loading history...
101
	}
102
103
	public function getACL() {
104
		$acl =  [
105
			[
106
				'privilege' => '{DAV:}read',
107
				'principal' => $this->getOwner(),
108
				'protected' => true,
109
			],[
110
				'privilege' => '{DAV:}write',
111
				'principal' => $this->getOwner(),
112
				'protected' => true,
113
			]
114
		];
115
116
		if ($this->getOwner() === 'principals/system/system') {
117
			$acl[] = [
118
				'privilege' => '{DAV:}read',
119
				'principal' => '{DAV:}authenticated',
120
				'protected' => true,
121
			];
122
		}
123
124
		if (!$this->isShared()) {
125
			return $acl;
126
		}
127
128
		if ($this->getOwner() !== parent::getOwner()) {
129
			$acl[] =  [
130
					'privilege' => '{DAV:}read',
131
					'principal' => parent::getOwner(),
132
					'protected' => true,
133
				];
134
			if ($this->canWrite()) {
135
				$acl[] = [
136
					'privilege' => '{DAV:}write',
137
					'principal' => parent::getOwner(),
138
					'protected' => true,
139
				];
140
			}
141
		}
142
143
		$acl = $this->carddavBackend->applyShareAcl($this->getResourceId(), $acl);
0 ignored issues
show
Bug introduced by
The method applyShareAcl() does not exist on Sabre\CardDAV\Backend\BackendInterface. It seems like you code against a sub-type of Sabre\CardDAV\Backend\BackendInterface such as OCA\DAV\CardDAV\CardDavBackend or OCA\DAV\CardDAV\CardDavBackend. ( Ignorable by Annotation )

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

143
		/** @scrutinizer ignore-call */ 
144
  $acl = $this->carddavBackend->applyShareAcl($this->getResourceId(), $acl);
Loading history...
144
		$allowedPrincipals = [$this->getOwner(), parent::getOwner(), 'principals/system/system'];
145
		return array_filter($acl, function($rule) use ($allowedPrincipals) {
146
			return \in_array($rule['principal'], $allowedPrincipals, true);
147
		});
148
	}
149
150
	public function getChildACL() {
151
		return $this->getACL();
152
	}
153
154
	public function getChild($name) {
155
156
		$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name);
157
		if (!$obj) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $obj of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
158
			throw new NotFound('Card not found');
159
		}
160
		$obj['acl'] = $this->getChildACL();
161
		return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
162
163
	}
164
165
	/**
166
	 * @return int
167
	 */
168
	public function getResourceId() {
169
		return $this->addressBookInfo['id'];
170
	}
171
172
	public function getOwner() {
173
		if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
174
			return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'];
175
		}
176
		return parent::getOwner();
177
	}
178
179
	public function delete() {
180
		if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
181
			$principal = 'principal:' . parent::getOwner();
182
			$shares = $this->carddavBackend->getShares($this->getResourceId());
183
			$shares = array_filter($shares, function($share) use ($principal){
184
				return $share['href'] === $principal;
185
			});
186
			if (empty($shares)) {
187
				throw new Forbidden();
188
			}
189
190
			$this->carddavBackend->updateShares($this, [], [
191
				$principal
192
			]);
193
			return;
194
		}
195
		parent::delete();
196
	}
197
198
	public function propPatch(PropPatch $propPatch) {
199
		if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
200
			throw new Forbidden();
201
		}
202
		parent::propPatch($propPatch);
203
	}
204
205
	public function getContactsGroups() {
206
		return $this->carddavBackend->collectCardProperties($this->getResourceId(), 'CATEGORIES');
0 ignored issues
show
Bug introduced by
The method collectCardProperties() does not exist on Sabre\CardDAV\Backend\BackendInterface. It seems like you code against a sub-type of Sabre\CardDAV\Backend\BackendInterface such as OCA\DAV\CardDAV\CardDavBackend or OCA\DAV\CardDAV\CardDavBackend. ( Ignorable by Annotation )

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

206
		return $this->carddavBackend->/** @scrutinizer ignore-call */ collectCardProperties($this->getResourceId(), 'CATEGORIES');
Loading history...
207
	}
208
209
	private function isShared() {
210
		if (!isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
211
			return false;
212
		}
213
214
		return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'] !== $this->addressBookInfo['principaluri'];
215
	}
216
217
	private function canWrite() {
218
		if (isset($this->addressBookInfo['{http://owncloud.org/ns}read-only'])) {
219
			return !$this->addressBookInfo['{http://owncloud.org/ns}read-only'];
220
		}
221
		return true;
222
	}
223
224
	public function getChanges($syncToken, $syncLevel, $limit = null) {
225
		if (!$syncToken && $limit) {
226
			throw new UnsupportedLimitOnInitialSyncException();
227
		}
228
229
		return parent::getChanges($syncToken, $syncLevel, $limit);
230
	}
231
}
232