Completed
Pull Request — stable9 (#1208)
by Joas
31:05 queued 22:55
created

AddressBookImpl::vCard2Array()   D

Complexity

Conditions 9
Paths 14

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 19
c 1
b 0
f 0
nc 14
nop 1
dl 0
loc 34
rs 4.909
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Björn Schießle <[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
24
namespace OCA\DAV\CardDAV;
25
26
use OCP\Constants;
27
use OCP\IAddressBook;
28
use Sabre\VObject\Component\VCard;
29
use Sabre\VObject\Property;
30
use Sabre\VObject\Property\Text;
31
use Sabre\VObject\Reader;
32
use Sabre\VObject\UUIDUtil;
33
34
class AddressBookImpl implements IAddressBook {
35
36
	/** @var CardDavBackend */
37
	private $backend;
38
39
	/** @var array */
40
	private $addressBookInfo;
41
42
	/** @var AddressBook */
43
	private $addressBook;
44
45
	/**
46
	 * AddressBookImpl constructor.
47
	 *
48
	 * @param AddressBook $addressBook
49
	 * @param array $addressBookInfo
50
	 * @param CardDavBackend $backend
51
	 */
52
	public function __construct(
53
			AddressBook $addressBook,
54
			array $addressBookInfo,
55
			CardDavBackend $backend) {
56
57
		$this->addressBook = $addressBook;
58
		$this->addressBookInfo = $addressBookInfo;
59
		$this->backend = $backend;
60
	}
61
62
	/**
63
	 * @return string defining the technical unique key
64
	 * @since 5.0.0
65
	 */
66
	public function getKey() {
67
		return $this->addressBookInfo['id'];
68
	}
69
70
	/**
71
	 * In comparison to getKey() this function returns a human readable (maybe translated) name
72
	 *
73
	 * @return mixed
74
	 * @since 5.0.0
75
	 */
76
	public function getDisplayName() {
77
		return $this->addressBookInfo['{DAV:}displayname'];
78
	}
79
80
	/**
81
	 * @param string $pattern which should match within the $searchProperties
82
	 * @param array $searchProperties defines the properties within the query pattern should match
83
	 * @param array $options - for future use. One should always have options!
84
	 * @return array an array of contacts which are arrays of key-value-pairs
85
	 * @since 5.0.0
86
	 */
87
	public function search($pattern, $searchProperties, $options) {
88
		$result = $this->backend->search($this->getKey(), $pattern, $searchProperties);
89
90
		$vCards = [];
91
		foreach ($result as $cardData) {
92
			$vCards[] = $this->vCard2Array($this->readCard($cardData));
93
		}
94
95
		return $vCards;
96
	}
97
98
	/**
99
	 * @param array $properties this array if key-value-pairs defines a contact
100
	 * @return array an array representing the contact just created or updated
101
	 * @since 5.0.0
102
	 */
103
	public function createOrUpdate($properties) {
104
		$update = false;
105
		if (!isset($properties['UID'])) { // create a new contact
106
			$uid = $this->createUid();
107
			$uri = $uid . '.vcf';
108
			$vCard = $this->createEmptyVCard($uid);
109
		} else { // update existing contact
110
			$uid = $properties['UID'];
111
			$uri = $uid . '.vcf';
112
			$vCardData = $this->backend->getCard($this->getKey(), $uri);
113
			$vCard = $this->readCard($vCardData['carddata']);
114
			$update = true;
115
		}
116
117
		foreach ($properties as $key => $value) {
118
			$vCard->$key = $vCard->createProperty($key, $value);
119
		}
120
121
		if ($update) {
122
			$this->backend->updateCard($this->getKey(), $uri, $vCard->serialize());
123
		} else {
124
			$this->backend->createCard($this->getKey(), $uri, $vCard->serialize());
125
		}
126
127
		return $this->vCard2Array($vCard);
128
129
	}
130
131
	/**
132
	 * @return mixed
133
	 * @since 5.0.0
134
	 */
135
	public function getPermissions() {
136
		$permissions = $this->addressBook->getACL();
137
		$result = 0;
138
		foreach ($permissions as $permission) {
139
			switch($permission['privilege']) {
140
				case '{DAV:}read':
141
					$result |= Constants::PERMISSION_READ;
142
					break;
143
				case '{DAV:}write':
144
					$result |= Constants::PERMISSION_CREATE;
145
					$result |= Constants::PERMISSION_UPDATE;
146
					break;
147
				case '{DAV:}all':
148
					$result |= Constants::PERMISSION_ALL;
149
					break;
150
			}
151
		}
152
153
		return $result;
154
	}
155
156
	/**
157
	 * @param object $id the unique identifier to a contact
158
	 * @return bool successful or not
159
	 * @since 5.0.0
160
	 */
161
	public function delete($id) {
162
		$uri = $this->backend->getCardUri($id);
163
		return $this->backend->deleteCard($this->addressBookInfo['id'], $uri);
164
	}
165
166
	/**
167
	 * read vCard data into a vCard object
168
	 *
169
	 * @param string $cardData
170
	 * @return VCard
171
	 */
172
	protected function readCard($cardData) {
173
		return  Reader::read($cardData);
174
	}
175
176
	/**
177
	 * create UID for contact
178
	 *
179
	 * @return string
180
	 */
181
	protected function createUid() {
182
		do {
183
			$uid = $this->getUid();
184
			$contact = $this->backend->getContact($this->getKey(), $uid . '.vcf');
185
		} while (!empty($contact));
186
187
		return $uid;
188
	}
189
190
	/**
191
	 * getUid is only there for testing, use createUid instead
192
	 */
193
	protected function getUid() {
194
		return UUIDUtil::getUUID();
195
	}
196
197
	/**
198
	 * create empty vcard
199
	 *
200
	 * @param string $uid
201
	 * @return VCard
202
	 */
203
	protected function createEmptyVCard($uid) {
204
		$vCard = new VCard();
205
		$vCard->add(new Text($vCard, 'UID', $uid));
206
		return $vCard;
207
	}
208
209
	/**
210
	 * create array with all vCard properties
211
	 *
212
	 * @param VCard $vCard
213
	 * @return array
214
	 */
215
	protected function vCard2Array(VCard $vCard) {
216
		$result = [];
217
		foreach ($vCard->children as $property) {
218
			/** @var \Sabre\VObject\Property\Unknown $property */
219
			if ($property->name === 'X-SOCIALPROFILE') {
220
				$type = $this->getTypeFromProperty($property);
221
222
				// Type is the social network, when it's empty we don't need this.
223
				if ($type !== null) {
224
					if (!isset($result[$property->name])) {
225
						$result[$property->name] = [];
226
					}
227
					$result[$property->name][$type] = $property->getValue();
228
				}
229
230
				// The following properties can be set multiple times
231
			} else if (in_array($property->name, ['CLOUD', 'EMAIL', 'IMPP', 'TEL', 'URL'])) {
232
				if (!isset($result[$property->name])) {
233
					$result[$property->name] = [];
234
				}
235
236
				$result[$property->name][] = $property->getValue();
237
238
			} else {
239
				$result[$property->name] = $property->getValue();
240
			}
241
		}
242
243
		if ($this->addressBookInfo['principaluri'] === 'principals/system/system' &&
244
			$this->addressBookInfo['uri'] === 'system') {
245
			$result['isLocalSystemBook'] = true;
246
		}
247
		return $result;
248
	}
249
250
	/**
251
	 * Get the type of the current property
252
	 *
253
	 * @param Property $property
254
	 * @return null|string
255
	 */
256
	protected function getTypeFromProperty(Property $property) {
257
		$parameters = $property->parameters();
258
		// Type is the social network, when it's empty we don't need this.
259
		if (isset($parameters['TYPE'])) {
260
			/** @var \Sabre\VObject\Parameter $type */
261
			$type = $parameters['TYPE'];
262
			return $type->getValue();
263
		}
264
265
		return null;
266
	}
267
}
268