Passed
Push — master ( 54f4c0...eadfa9 )
by Robin
12:16
created
apps/dav/lib/CardDAV/AddressBookImpl.php 2 patches
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -111,7 +111,7 @@  discard block
 block discarded – undo
111 111
 		$update = false;
112 112
 		if (!isset($properties['URI'])) { // create a new contact
113 113
 			$uid = $this->createUid();
114
-			$uri = $uid . '.vcf';
114
+			$uri = $uid.'.vcf';
115 115
 			$vCard = $this->createEmptyVCard($uid);
116 116
 		} else { // update existing contact
117 117
 			$uri = $properties['URI'];
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
 		$permissions = $this->addressBook->getACL();
143 143
 		$result = 0;
144 144
 		foreach ($permissions as $permission) {
145
-			switch($permission['privilege']) {
145
+			switch ($permission['privilege']) {
146 146
 				case '{DAV:}read':
147 147
 					$result |= Constants::PERMISSION_READ;
148 148
 					break;
@@ -187,7 +187,7 @@  discard block
 block discarded – undo
187 187
 	protected function createUid() {
188 188
 		do {
189 189
 			$uid = $this->getUid();
190
-			$contact = $this->backend->getContact($this->getKey(), $uid . '.vcf');
190
+			$contact = $this->backend->getContact($this->getKey(), $uid.'.vcf');
191 191
 		} while (!empty($contact));
192 192
 
193 193
 		return $uid;
@@ -227,15 +227,15 @@  discard block
 block discarded – undo
227 227
 		foreach ($vCard->children() as $property) {
228 228
 			if ($property->name === 'PHOTO' && $property->getValueType() === 'BINARY') {
229 229
 				$url = $this->urlGenerator->getAbsoluteURL(
230
-					$this->urlGenerator->linkTo('', 'remote.php') . '/dav/');
230
+					$this->urlGenerator->linkTo('', 'remote.php').'/dav/');
231 231
 				$url .= implode('/', [
232 232
 					'addressbooks',
233 233
 					substr($this->addressBookInfo['principaluri'], 11), //cut off 'principals/'
234 234
 					$this->addressBookInfo['uri'],
235 235
 					$uri
236
-				]) . '?photo';
236
+				]).'?photo';
237 237
 
238
-				$result['PHOTO'] = 'VALUE=uri:' . $url;
238
+				$result['PHOTO'] = 'VALUE=uri:'.$url;
239 239
 
240 240
 			} else if ($property->name === 'X-SOCIALPROFILE') {
241 241
 				$type = $this->getTypeFromProperty($property);
Please login to merge, or discard this patch.
Indentation   +274 added lines, -274 removed lines patch added patch discarded remove patch
@@ -35,278 +35,278 @@
 block discarded – undo
35 35
 
36 36
 class AddressBookImpl implements IAddressBook {
37 37
 
38
-	/** @var CardDavBackend */
39
-	private $backend;
40
-
41
-	/** @var array */
42
-	private $addressBookInfo;
43
-
44
-	/** @var AddressBook */
45
-	private $addressBook;
46
-
47
-	/** @var IURLGenerator */
48
-	private $urlGenerator;
49
-
50
-	/**
51
-	 * AddressBookImpl constructor.
52
-	 *
53
-	 * @param AddressBook $addressBook
54
-	 * @param array $addressBookInfo
55
-	 * @param CardDavBackend $backend
56
-	 * @param IUrlGenerator $urlGenerator
57
-	 */
58
-	public function __construct(
59
-			AddressBook $addressBook,
60
-			array $addressBookInfo,
61
-			CardDavBackend $backend,
62
-			IURLGenerator $urlGenerator) {
63
-
64
-		$this->addressBook = $addressBook;
65
-		$this->addressBookInfo = $addressBookInfo;
66
-		$this->backend = $backend;
67
-		$this->urlGenerator = $urlGenerator;
68
-	}
69
-
70
-	/**
71
-	 * @return string defining the technical unique key
72
-	 * @since 5.0.0
73
-	 */
74
-	public function getKey() {
75
-		return $this->addressBookInfo['id'];
76
-	}
77
-
78
-	/**
79
-	 * In comparison to getKey() this function returns a human readable (maybe translated) name
80
-	 *
81
-	 * @return mixed
82
-	 * @since 5.0.0
83
-	 */
84
-	public function getDisplayName() {
85
-		return $this->addressBookInfo['{DAV:}displayname'];
86
-	}
87
-
88
-	/**
89
-	 * @param string $pattern which should match within the $searchProperties
90
-	 * @param array $searchProperties defines the properties within the query pattern should match
91
-	 * @param array $options Options to define the output format
92
-	 * 	- types boolean (since 15.0.0) If set to true, fields that come with a TYPE property will be an array
93
-	 *    example: ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['type => 'HOME', 'value' => '[email protected]']]
94
-	 * @return array an array of contacts which are arrays of key-value-pairs
95
-	 *  example result:
96
-	 *  [
97
-	 *		['id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => '[email protected]', 'GEO' => '37.386013;-122.082932'],
98
-	 *		['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['[email protected]', '[email protected]']]
99
-	 *	]
100
-	 * @return array an array of contacts which are arrays of key-value-pairs
101
-	 * @since 5.0.0
102
-	 */
103
-	public function search($pattern, $searchProperties, $options) {
104
-		$results = $this->backend->search($this->getKey(), $pattern, $searchProperties);
105
-
106
-		$withTypes = \array_key_exists('types', $options) && $options['types'] === true;
107
-
108
-		$vCards = [];
109
-		foreach ($results as $result) {
110
-			$vCards[] = $this->vCard2Array($result['uri'], $this->readCard($result['carddata']), $withTypes);
111
-		}
112
-
113
-		return $vCards;
114
-	}
115
-
116
-	/**
117
-	 * @param array $properties this array if key-value-pairs defines a contact
118
-	 * @return array an array representing the contact just created or updated
119
-	 * @since 5.0.0
120
-	 */
121
-	public function createOrUpdate($properties) {
122
-		$update = false;
123
-		if (!isset($properties['URI'])) { // create a new contact
124
-			$uid = $this->createUid();
125
-			$uri = $uid . '.vcf';
126
-			$vCard = $this->createEmptyVCard($uid);
127
-		} else { // update existing contact
128
-			$uri = $properties['URI'];
129
-			$vCardData = $this->backend->getCard($this->getKey(), $uri);
130
-			$vCard = $this->readCard($vCardData['carddata']);
131
-			$update = true;
132
-		}
133
-
134
-		foreach ($properties as $key => $value) {
135
-			$vCard->$key = $vCard->createProperty($key, $value);
136
-		}
137
-
138
-		if ($update) {
139
-			$this->backend->updateCard($this->getKey(), $uri, $vCard->serialize());
140
-		} else {
141
-			$this->backend->createCard($this->getKey(), $uri, $vCard->serialize());
142
-		}
143
-
144
-		return $this->vCard2Array($uri, $vCard);
145
-
146
-	}
147
-
148
-	/**
149
-	 * @return mixed
150
-	 * @since 5.0.0
151
-	 */
152
-	public function getPermissions() {
153
-		$permissions = $this->addressBook->getACL();
154
-		$result = 0;
155
-		foreach ($permissions as $permission) {
156
-			switch($permission['privilege']) {
157
-				case '{DAV:}read':
158
-					$result |= Constants::PERMISSION_READ;
159
-					break;
160
-				case '{DAV:}write':
161
-					$result |= Constants::PERMISSION_CREATE;
162
-					$result |= Constants::PERMISSION_UPDATE;
163
-					break;
164
-				case '{DAV:}all':
165
-					$result |= Constants::PERMISSION_ALL;
166
-					break;
167
-			}
168
-		}
169
-
170
-		return $result;
171
-	}
172
-
173
-	/**
174
-	 * @param object $id the unique identifier to a contact
175
-	 * @return bool successful or not
176
-	 * @since 5.0.0
177
-	 */
178
-	public function delete($id) {
179
-		$uri = $this->backend->getCardUri($id);
180
-		return $this->backend->deleteCard($this->addressBookInfo['id'], $uri);
181
-	}
182
-
183
-	/**
184
-	 * read vCard data into a vCard object
185
-	 *
186
-	 * @param string $cardData
187
-	 * @return VCard
188
-	 */
189
-	protected function readCard($cardData) {
190
-		return  Reader::read($cardData);
191
-	}
192
-
193
-	/**
194
-	 * create UID for contact
195
-	 *
196
-	 * @return string
197
-	 */
198
-	protected function createUid() {
199
-		do {
200
-			$uid = $this->getUid();
201
-			$contact = $this->backend->getContact($this->getKey(), $uid . '.vcf');
202
-		} while (!empty($contact));
203
-
204
-		return $uid;
205
-	}
206
-
207
-	/**
208
-	 * getUid is only there for testing, use createUid instead
209
-	 */
210
-	protected function getUid() {
211
-		return UUIDUtil::getUUID();
212
-	}
213
-
214
-	/**
215
-	 * create empty vcard
216
-	 *
217
-	 * @param string $uid
218
-	 * @return VCard
219
-	 */
220
-	protected function createEmptyVCard($uid) {
221
-		$vCard = new VCard();
222
-		$vCard->UID = $uid;
223
-		return $vCard;
224
-	}
225
-
226
-	/**
227
-	 * create array with all vCard properties
228
-	 *
229
-	 * @param string $uri
230
-	 * @param VCard $vCard
231
-	 * @return array
232
-	 */
233
-	protected function vCard2Array($uri, VCard $vCard, $withTypes = false) {
234
-		$result = [
235
-			'URI' => $uri,
236
-		];
237
-
238
-		foreach ($vCard->children() as $property) {
239
-			if ($property->name === 'PHOTO' && $property->getValueType() === 'BINARY') {
240
-				$url = $this->urlGenerator->getAbsoluteURL(
241
-					$this->urlGenerator->linkTo('', 'remote.php') . '/dav/');
242
-				$url .= implode('/', [
243
-					'addressbooks',
244
-					substr($this->addressBookInfo['principaluri'], 11), //cut off 'principals/'
245
-					$this->addressBookInfo['uri'],
246
-					$uri
247
-				]) . '?photo';
248
-
249
-				$result['PHOTO'] = 'VALUE=uri:' . $url;
250
-
251
-			} else if ($property->name === 'X-SOCIALPROFILE') {
252
-				$type = $this->getTypeFromProperty($property);
253
-
254
-				// Type is the social network, when it's empty we don't need this.
255
-				if ($type !== null) {
256
-					if (!isset($result[$property->name])) {
257
-						$result[$property->name] = [];
258
-					}
259
-					$result[$property->name][$type] = $property->getValue();
260
-				}
261
-
262
-			// The following properties can be set multiple times
263
-			} else if (in_array($property->name, ['CLOUD', 'EMAIL', 'IMPP', 'TEL', 'URL'])) {
264
-				if (!isset($result[$property->name])) {
265
-					$result[$property->name] = [];
266
-				}
267
-
268
-				$type = $this->getTypeFromProperty($property);
269
-				if ($withTypes) {
270
-					$result[$property->name][] = [
271
-						'type' => $type,
272
-						'value' => $property->getValue()
273
-						];
274
-				} else {
275
-					$result[$property->name][] = $property->getValue();
276
-				}
277
-
278
-
279
-			} else {
280
-				$result[$property->name] = $property->getValue();
281
-			}
282
-		}
283
-
284
-		if (
285
-			$this->addressBookInfo['principaluri'] === 'principals/system/system' && (
286
-				$this->addressBookInfo['uri'] === 'system' ||
287
-				$this->addressBookInfo['{DAV:}displayname'] === $this->urlGenerator->getBaseUrl()
288
-			)
289
-		) {
290
-			$result['isLocalSystemBook'] = true;
291
-		}
292
-		return $result;
293
-	}
294
-
295
-	/**
296
-	 * Get the type of the current property
297
-	 *
298
-	 * @param Property $property
299
-	 * @return null|string
300
-	 */
301
-	protected function getTypeFromProperty(Property $property) {
302
-		$parameters = $property->parameters();
303
-		// Type is the social network, when it's empty we don't need this.
304
-		if (isset($parameters['TYPE'])) {
305
-			/** @var \Sabre\VObject\Parameter $type */
306
-			$type = $parameters['TYPE'];
307
-			return $type->getValue();
308
-		}
309
-
310
-		return null;
311
-	}
38
+    /** @var CardDavBackend */
39
+    private $backend;
40
+
41
+    /** @var array */
42
+    private $addressBookInfo;
43
+
44
+    /** @var AddressBook */
45
+    private $addressBook;
46
+
47
+    /** @var IURLGenerator */
48
+    private $urlGenerator;
49
+
50
+    /**
51
+     * AddressBookImpl constructor.
52
+     *
53
+     * @param AddressBook $addressBook
54
+     * @param array $addressBookInfo
55
+     * @param CardDavBackend $backend
56
+     * @param IUrlGenerator $urlGenerator
57
+     */
58
+    public function __construct(
59
+            AddressBook $addressBook,
60
+            array $addressBookInfo,
61
+            CardDavBackend $backend,
62
+            IURLGenerator $urlGenerator) {
63
+
64
+        $this->addressBook = $addressBook;
65
+        $this->addressBookInfo = $addressBookInfo;
66
+        $this->backend = $backend;
67
+        $this->urlGenerator = $urlGenerator;
68
+    }
69
+
70
+    /**
71
+     * @return string defining the technical unique key
72
+     * @since 5.0.0
73
+     */
74
+    public function getKey() {
75
+        return $this->addressBookInfo['id'];
76
+    }
77
+
78
+    /**
79
+     * In comparison to getKey() this function returns a human readable (maybe translated) name
80
+     *
81
+     * @return mixed
82
+     * @since 5.0.0
83
+     */
84
+    public function getDisplayName() {
85
+        return $this->addressBookInfo['{DAV:}displayname'];
86
+    }
87
+
88
+    /**
89
+     * @param string $pattern which should match within the $searchProperties
90
+     * @param array $searchProperties defines the properties within the query pattern should match
91
+     * @param array $options Options to define the output format
92
+     * 	- types boolean (since 15.0.0) If set to true, fields that come with a TYPE property will be an array
93
+     *    example: ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['type => 'HOME', 'value' => '[email protected]']]
94
+     * @return array an array of contacts which are arrays of key-value-pairs
95
+     *  example result:
96
+     *  [
97
+     *		['id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => '[email protected]', 'GEO' => '37.386013;-122.082932'],
98
+     *		['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['[email protected]', '[email protected]']]
99
+     *	]
100
+     * @return array an array of contacts which are arrays of key-value-pairs
101
+     * @since 5.0.0
102
+     */
103
+    public function search($pattern, $searchProperties, $options) {
104
+        $results = $this->backend->search($this->getKey(), $pattern, $searchProperties);
105
+
106
+        $withTypes = \array_key_exists('types', $options) && $options['types'] === true;
107
+
108
+        $vCards = [];
109
+        foreach ($results as $result) {
110
+            $vCards[] = $this->vCard2Array($result['uri'], $this->readCard($result['carddata']), $withTypes);
111
+        }
112
+
113
+        return $vCards;
114
+    }
115
+
116
+    /**
117
+     * @param array $properties this array if key-value-pairs defines a contact
118
+     * @return array an array representing the contact just created or updated
119
+     * @since 5.0.0
120
+     */
121
+    public function createOrUpdate($properties) {
122
+        $update = false;
123
+        if (!isset($properties['URI'])) { // create a new contact
124
+            $uid = $this->createUid();
125
+            $uri = $uid . '.vcf';
126
+            $vCard = $this->createEmptyVCard($uid);
127
+        } else { // update existing contact
128
+            $uri = $properties['URI'];
129
+            $vCardData = $this->backend->getCard($this->getKey(), $uri);
130
+            $vCard = $this->readCard($vCardData['carddata']);
131
+            $update = true;
132
+        }
133
+
134
+        foreach ($properties as $key => $value) {
135
+            $vCard->$key = $vCard->createProperty($key, $value);
136
+        }
137
+
138
+        if ($update) {
139
+            $this->backend->updateCard($this->getKey(), $uri, $vCard->serialize());
140
+        } else {
141
+            $this->backend->createCard($this->getKey(), $uri, $vCard->serialize());
142
+        }
143
+
144
+        return $this->vCard2Array($uri, $vCard);
145
+
146
+    }
147
+
148
+    /**
149
+     * @return mixed
150
+     * @since 5.0.0
151
+     */
152
+    public function getPermissions() {
153
+        $permissions = $this->addressBook->getACL();
154
+        $result = 0;
155
+        foreach ($permissions as $permission) {
156
+            switch($permission['privilege']) {
157
+                case '{DAV:}read':
158
+                    $result |= Constants::PERMISSION_READ;
159
+                    break;
160
+                case '{DAV:}write':
161
+                    $result |= Constants::PERMISSION_CREATE;
162
+                    $result |= Constants::PERMISSION_UPDATE;
163
+                    break;
164
+                case '{DAV:}all':
165
+                    $result |= Constants::PERMISSION_ALL;
166
+                    break;
167
+            }
168
+        }
169
+
170
+        return $result;
171
+    }
172
+
173
+    /**
174
+     * @param object $id the unique identifier to a contact
175
+     * @return bool successful or not
176
+     * @since 5.0.0
177
+     */
178
+    public function delete($id) {
179
+        $uri = $this->backend->getCardUri($id);
180
+        return $this->backend->deleteCard($this->addressBookInfo['id'], $uri);
181
+    }
182
+
183
+    /**
184
+     * read vCard data into a vCard object
185
+     *
186
+     * @param string $cardData
187
+     * @return VCard
188
+     */
189
+    protected function readCard($cardData) {
190
+        return  Reader::read($cardData);
191
+    }
192
+
193
+    /**
194
+     * create UID for contact
195
+     *
196
+     * @return string
197
+     */
198
+    protected function createUid() {
199
+        do {
200
+            $uid = $this->getUid();
201
+            $contact = $this->backend->getContact($this->getKey(), $uid . '.vcf');
202
+        } while (!empty($contact));
203
+
204
+        return $uid;
205
+    }
206
+
207
+    /**
208
+     * getUid is only there for testing, use createUid instead
209
+     */
210
+    protected function getUid() {
211
+        return UUIDUtil::getUUID();
212
+    }
213
+
214
+    /**
215
+     * create empty vcard
216
+     *
217
+     * @param string $uid
218
+     * @return VCard
219
+     */
220
+    protected function createEmptyVCard($uid) {
221
+        $vCard = new VCard();
222
+        $vCard->UID = $uid;
223
+        return $vCard;
224
+    }
225
+
226
+    /**
227
+     * create array with all vCard properties
228
+     *
229
+     * @param string $uri
230
+     * @param VCard $vCard
231
+     * @return array
232
+     */
233
+    protected function vCard2Array($uri, VCard $vCard, $withTypes = false) {
234
+        $result = [
235
+            'URI' => $uri,
236
+        ];
237
+
238
+        foreach ($vCard->children() as $property) {
239
+            if ($property->name === 'PHOTO' && $property->getValueType() === 'BINARY') {
240
+                $url = $this->urlGenerator->getAbsoluteURL(
241
+                    $this->urlGenerator->linkTo('', 'remote.php') . '/dav/');
242
+                $url .= implode('/', [
243
+                    'addressbooks',
244
+                    substr($this->addressBookInfo['principaluri'], 11), //cut off 'principals/'
245
+                    $this->addressBookInfo['uri'],
246
+                    $uri
247
+                ]) . '?photo';
248
+
249
+                $result['PHOTO'] = 'VALUE=uri:' . $url;
250
+
251
+            } else if ($property->name === 'X-SOCIALPROFILE') {
252
+                $type = $this->getTypeFromProperty($property);
253
+
254
+                // Type is the social network, when it's empty we don't need this.
255
+                if ($type !== null) {
256
+                    if (!isset($result[$property->name])) {
257
+                        $result[$property->name] = [];
258
+                    }
259
+                    $result[$property->name][$type] = $property->getValue();
260
+                }
261
+
262
+            // The following properties can be set multiple times
263
+            } else if (in_array($property->name, ['CLOUD', 'EMAIL', 'IMPP', 'TEL', 'URL'])) {
264
+                if (!isset($result[$property->name])) {
265
+                    $result[$property->name] = [];
266
+                }
267
+
268
+                $type = $this->getTypeFromProperty($property);
269
+                if ($withTypes) {
270
+                    $result[$property->name][] = [
271
+                        'type' => $type,
272
+                        'value' => $property->getValue()
273
+                        ];
274
+                } else {
275
+                    $result[$property->name][] = $property->getValue();
276
+                }
277
+
278
+
279
+            } else {
280
+                $result[$property->name] = $property->getValue();
281
+            }
282
+        }
283
+
284
+        if (
285
+            $this->addressBookInfo['principaluri'] === 'principals/system/system' && (
286
+                $this->addressBookInfo['uri'] === 'system' ||
287
+                $this->addressBookInfo['{DAV:}displayname'] === $this->urlGenerator->getBaseUrl()
288
+            )
289
+        ) {
290
+            $result['isLocalSystemBook'] = true;
291
+        }
292
+        return $result;
293
+    }
294
+
295
+    /**
296
+     * Get the type of the current property
297
+     *
298
+     * @param Property $property
299
+     * @return null|string
300
+     */
301
+    protected function getTypeFromProperty(Property $property) {
302
+        $parameters = $property->parameters();
303
+        // Type is the social network, when it's empty we don't need this.
304
+        if (isset($parameters['TYPE'])) {
305
+            /** @var \Sabre\VObject\Parameter $type */
306
+            $type = $parameters['TYPE'];
307
+            return $type->getValue();
308
+        }
309
+
310
+        return null;
311
+    }
312 312
 }
Please login to merge, or discard this patch.
apps/dav/lib/CardDAV/Xml/Groups.php 2 patches
Indentation   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -26,21 +26,21 @@
 block discarded – undo
26 26
 use Sabre\Xml\Writer;
27 27
 
28 28
 class Groups implements XmlSerializable {
29
-	const NS_OWNCLOUD = 'http://owncloud.org/ns';
29
+    const NS_OWNCLOUD = 'http://owncloud.org/ns';
30 30
 
31
-	/** @var string[] of TYPE:CHECKSUM */
32
-	private $groups;
31
+    /** @var string[] of TYPE:CHECKSUM */
32
+    private $groups;
33 33
 
34
-	/**
35
-	 * @param string $groups
36
-	 */
37
-	public function __construct($groups) {
38
-		$this->groups = $groups;
39
-	}
34
+    /**
35
+     * @param string $groups
36
+     */
37
+    public function __construct($groups) {
38
+        $this->groups = $groups;
39
+    }
40 40
 
41
-	function xmlSerialize(Writer $writer) {
42
-		foreach ($this->groups as $group) {
43
-			$writer->writeElement('{' . self::NS_OWNCLOUD . '}group', $group);
44
-		}
45
-	}
41
+    function xmlSerialize(Writer $writer) {
42
+        foreach ($this->groups as $group) {
43
+            $writer->writeElement('{' . self::NS_OWNCLOUD . '}group', $group);
44
+        }
45
+    }
46 46
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -40,7 +40,7 @@
 block discarded – undo
40 40
 
41 41
 	function xmlSerialize(Writer $writer) {
42 42
 		foreach ($this->groups as $group) {
43
-			$writer->writeElement('{' . self::NS_OWNCLOUD . '}group', $group);
43
+			$writer->writeElement('{'.self::NS_OWNCLOUD.'}group', $group);
44 44
 		}
45 45
 	}
46 46
 }
Please login to merge, or discard this patch.
apps/dav/lib/CardDAV/AddressBookRoot.php 1 patch
Indentation   +33 added lines, -33 removed lines patch added patch discarded remove patch
@@ -25,46 +25,46 @@
 block discarded – undo
25 25
 
26 26
 class AddressBookRoot extends \Sabre\CardDAV\AddressBookRoot {
27 27
 
28
-	/** @var IL10N */
29
-	protected $l10n;
28
+    /** @var IL10N */
29
+    protected $l10n;
30 30
 
31
-	/**
32
-	 * @param \Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend
33
-	 * @param \Sabre\CardDAV\Backend\BackendInterface $carddavBackend
34
-	 * @param string $principalPrefix
35
-	 */
36
-	public function __construct(\Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend, \Sabre\CardDAV\Backend\BackendInterface $carddavBackend, $principalPrefix = 'principals') {
37
-		parent::__construct($principalBackend, $carddavBackend, $principalPrefix);
38
-		$this->l10n = \OC::$server->getL10N('dav');
39
-	}
31
+    /**
32
+     * @param \Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend
33
+     * @param \Sabre\CardDAV\Backend\BackendInterface $carddavBackend
34
+     * @param string $principalPrefix
35
+     */
36
+    public function __construct(\Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend, \Sabre\CardDAV\Backend\BackendInterface $carddavBackend, $principalPrefix = 'principals') {
37
+        parent::__construct($principalBackend, $carddavBackend, $principalPrefix);
38
+        $this->l10n = \OC::$server->getL10N('dav');
39
+    }
40 40
 
41
-	/**
42
-	 * This method returns a node for a principal.
43
-	 *
44
-	 * The passed array contains principal information, and is guaranteed to
45
-	 * at least contain a uri item. Other properties may or may not be
46
-	 * supplied by the authentication backend.
47
-	 *
48
-	 * @param array $principal
49
-	 * @return \Sabre\DAV\INode
50
-	 */
51
-	function getChildForPrincipal(array $principal) {
41
+    /**
42
+     * This method returns a node for a principal.
43
+     *
44
+     * The passed array contains principal information, and is guaranteed to
45
+     * at least contain a uri item. Other properties may or may not be
46
+     * supplied by the authentication backend.
47
+     *
48
+     * @param array $principal
49
+     * @return \Sabre\DAV\INode
50
+     */
51
+    function getChildForPrincipal(array $principal) {
52 52
 
53
-		return new UserAddressBooks($this->carddavBackend, $principal['uri'], $this->l10n);
53
+        return new UserAddressBooks($this->carddavBackend, $principal['uri'], $this->l10n);
54 54
 
55
-	}
55
+    }
56 56
 
57
-	function getName() {
57
+    function getName() {
58 58
 
59
-		if ($this->principalPrefix === 'principals') {
60
-			return parent::getName();
61
-		}
62
-		// Grabbing all the components of the principal path.
63
-		$parts = explode('/', $this->principalPrefix);
59
+        if ($this->principalPrefix === 'principals') {
60
+            return parent::getName();
61
+        }
62
+        // Grabbing all the components of the principal path.
63
+        $parts = explode('/', $this->principalPrefix);
64 64
 
65
-		// We are only interested in the second part.
66
-		return $parts[1];
65
+        // We are only interested in the second part.
66
+        return $parts[1];
67 67
 
68
-	}
68
+    }
69 69
 
70 70
 }
Please login to merge, or discard this patch.
apps/dav/lib/CardDAV/CardDavBackend.php 3 patches
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -745,7 +745,9 @@
 block discarded – undo
745 745
 		$stmt->execute([ $addressBookId ]);
746 746
 		$currentToken = $stmt->fetchColumn(0);
747 747
 
748
-		if (is_null($currentToken)) return null;
748
+		if (is_null($currentToken)) {
749
+		    return null;
750
+		}
749 751
 
750 752
 		$result = [
751 753
 			'syncToken' => $currentToken,
Please login to merge, or discard this patch.
Spacing   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
 			->from('addressbooks')
115 115
 			->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
116 116
 
117
-		return (int)$query->execute()->fetchColumn();
117
+		return (int) $query->execute()->fetchColumn();
118 118
 	}
119 119
 
120 120
 	/**
@@ -145,15 +145,15 @@  discard block
 block discarded – undo
145 145
 		$addressBooks = [];
146 146
 
147 147
 		$result = $query->execute();
148
-		while($row = $result->fetch()) {
148
+		while ($row = $result->fetch()) {
149 149
 			$addressBooks[$row['id']] = [
150 150
 				'id'  => $row['id'],
151 151
 				'uri' => $row['uri'],
152 152
 				'principaluri' => $this->convertPrincipal($row['principaluri'], false),
153 153
 				'{DAV:}displayname' => $row['displayname'],
154
-				'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
154
+				'{'.Plugin::NS_CARDDAV.'}addressbook-description' => $row['description'],
155 155
 				'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
156
-				'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
156
+				'{http://sabredav.org/ns}sync-token' => $row['synctoken'] ? $row['synctoken'] : '0',
157 157
 			];
158 158
 
159 159
 			$this->addOwnerPrincipal($addressBooks[$row['id']]);
@@ -165,7 +165,7 @@  discard block
 block discarded – undo
165 165
 		$principals = array_map(function($principal) {
166 166
 			return urldecode($principal);
167 167
 		}, $principals);
168
-		$principals[]= $principalUri;
168
+		$principals[] = $principalUri;
169 169
 
170 170
 		$query = $this->db->getQueryBuilder();
171 171
 		$result = $query->select(['a.id', 'a.uri', 'a.displayname', 'a.principaluri', 'a.description', 'a.synctoken', 's.access'])
@@ -177,8 +177,8 @@  discard block
 block discarded – undo
177 177
 			->setParameter('principaluri', $principals, IQueryBuilder::PARAM_STR_ARRAY)
178 178
 			->execute();
179 179
 
180
-		$readOnlyPropertyName = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only';
181
-		while($row = $result->fetch()) {
180
+		$readOnlyPropertyName = '{'.\OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD.'}read-only';
181
+		while ($row = $result->fetch()) {
182 182
 			if ($row['principaluri'] === $principalUri) {
183 183
 				continue;
184 184
 			}
@@ -197,18 +197,18 @@  discard block
 block discarded – undo
197 197
 			}
198 198
 
199 199
 			list(, $name) = \Sabre\Uri\split($row['principaluri']);
200
-			$uri = $row['uri'] . '_shared_by_' . $name;
201
-			$displayName = $row['displayname'] . ' (' . $this->getUserDisplayName($name) . ')';
200
+			$uri = $row['uri'].'_shared_by_'.$name;
201
+			$displayName = $row['displayname'].' ('.$this->getUserDisplayName($name).')';
202 202
 
203 203
 			$addressBooks[$row['id']] = [
204 204
 				'id'  => $row['id'],
205 205
 				'uri' => $uri,
206 206
 				'principaluri' => $principalUriOriginal,
207 207
 				'{DAV:}displayname' => $displayName,
208
-				'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
208
+				'{'.Plugin::NS_CARDDAV.'}addressbook-description' => $row['description'],
209 209
 				'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
210
-				'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
211
-				'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'],
210
+				'{http://sabredav.org/ns}sync-token' => $row['synctoken'] ? $row['synctoken'] : '0',
211
+				'{'.\OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD.'}owner-principal' => $row['principaluri'],
212 212
 				$readOnlyPropertyName => $readOnly,
213 213
 			];
214 214
 
@@ -229,15 +229,15 @@  discard block
 block discarded – undo
229 229
 		$addressBooks = [];
230 230
 
231 231
 		$result = $query->execute();
232
-		while($row = $result->fetch()) {
232
+		while ($row = $result->fetch()) {
233 233
 			$addressBooks[$row['id']] = [
234 234
 				'id'  => $row['id'],
235 235
 				'uri' => $row['uri'],
236 236
 				'principaluri' => $this->convertPrincipal($row['principaluri'], false),
237 237
 				'{DAV:}displayname' => $row['displayname'],
238
-				'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
238
+				'{'.Plugin::NS_CARDDAV.'}addressbook-description' => $row['description'],
239 239
 				'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
240
-				'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
240
+				'{http://sabredav.org/ns}sync-token' => $row['synctoken'] ? $row['synctoken'] : '0',
241 241
 			];
242 242
 
243 243
 			$this->addOwnerPrincipal($addressBooks[$row['id']]);
@@ -282,9 +282,9 @@  discard block
 block discarded – undo
282 282
 			'uri' => $row['uri'],
283 283
 			'principaluri' => $row['principaluri'],
284 284
 			'{DAV:}displayname' => $row['displayname'],
285
-			'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
285
+			'{'.Plugin::NS_CARDDAV.'}addressbook-description' => $row['description'],
286 286
 			'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
287
-			'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
287
+			'{http://sabredav.org/ns}sync-token' => $row['synctoken'] ? $row['synctoken'] : '0',
288 288
 		];
289 289
 
290 290
 		$this->addOwnerPrincipal($addressBook);
@@ -316,9 +316,9 @@  discard block
 block discarded – undo
316 316
 			'uri' => $row['uri'],
317 317
 			'principaluri' => $row['principaluri'],
318 318
 			'{DAV:}displayname' => $row['displayname'],
319
-			'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
319
+			'{'.Plugin::NS_CARDDAV.'}addressbook-description' => $row['description'],
320 320
 			'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
321
-			'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
321
+			'{http://sabredav.org/ns}sync-token' => $row['synctoken'] ? $row['synctoken'] : '0',
322 322
 		];
323 323
 
324 324
 		$this->addOwnerPrincipal($addressBook);
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
 	function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch) {
346 346
 		$supportedProperties = [
347 347
 			'{DAV:}displayname',
348
-			'{' . Plugin::NS_CARDDAV . '}addressbook-description',
348
+			'{'.Plugin::NS_CARDDAV.'}addressbook-description',
349 349
 		];
350 350
 
351 351
 		/**
@@ -354,13 +354,13 @@  discard block
 block discarded – undo
354 354
 		$propPatch->handle($supportedProperties, function($mutations) use ($addressBookId) {
355 355
 
356 356
 			$updates = [];
357
-			foreach($mutations as $property=>$newValue) {
357
+			foreach ($mutations as $property=>$newValue) {
358 358
 
359
-				switch($property) {
359
+				switch ($property) {
360 360
 					case '{DAV:}displayname' :
361 361
 						$updates['displayname'] = $newValue;
362 362
 						break;
363
-					case '{' . Plugin::NS_CARDDAV . '}addressbook-description' :
363
+					case '{'.Plugin::NS_CARDDAV.'}addressbook-description' :
364 364
 						$updates['description'] = $newValue;
365 365
 						break;
366 366
 				}
@@ -368,7 +368,7 @@  discard block
 block discarded – undo
368 368
 			$query = $this->db->getQueryBuilder();
369 369
 			$query->update('addressbooks');
370 370
 
371
-			foreach($updates as $key=>$value) {
371
+			foreach ($updates as $key=>$value) {
372 372
 				$query->set($key, $query->createNamedParameter($value));
373 373
 			}
374 374
 			$query->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
@@ -399,24 +399,24 @@  discard block
 block discarded – undo
399 399
 			'synctoken' => 1
400 400
 		];
401 401
 
402
-		foreach($properties as $property=>$newValue) {
402
+		foreach ($properties as $property=>$newValue) {
403 403
 
404
-			switch($property) {
404
+			switch ($property) {
405 405
 				case '{DAV:}displayname' :
406 406
 					$values['displayname'] = $newValue;
407 407
 					break;
408
-				case '{' . Plugin::NS_CARDDAV . '}addressbook-description' :
408
+				case '{'.Plugin::NS_CARDDAV.'}addressbook-description' :
409 409
 					$values['description'] = $newValue;
410 410
 					break;
411 411
 				default :
412
-					throw new BadRequest('Unknown property: ' . $property);
412
+					throw new BadRequest('Unknown property: '.$property);
413 413
 			}
414 414
 
415 415
 		}
416 416
 
417 417
 		// Fallback to make sure the displayname is set. Some clients may refuse
418 418
 		// to work with addressbooks not having a displayname.
419
-		if(is_null($values['displayname'])) {
419
+		if (is_null($values['displayname'])) {
420 420
 			$values['displayname'] = $url;
421 421
 		}
422 422
 
@@ -494,8 +494,8 @@  discard block
 block discarded – undo
494 494
 		$cards = [];
495 495
 
496 496
 		$result = $query->execute();
497
-		while($row = $result->fetch()) {
498
-			$row['etag'] = '"' . $row['etag'] . '"';
497
+		while ($row = $result->fetch()) {
498
+			$row['etag'] = '"'.$row['etag'].'"';
499 499
 			$row['carddata'] = $this->readBlob($row['carddata']);
500 500
 			$cards[] = $row;
501 501
 		}
@@ -529,7 +529,7 @@  discard block
 block discarded – undo
529 529
 		if (!$row) {
530 530
 			return false;
531 531
 		}
532
-		$row['etag'] = '"' . $row['etag'] . '"';
532
+		$row['etag'] = '"'.$row['etag'].'"';
533 533
 		$row['carddata'] = $this->readBlob($row['carddata']);
534 534
 
535 535
 		return $row;
@@ -566,7 +566,7 @@  discard block
 block discarded – undo
566 566
 			$result = $query->execute();
567 567
 
568 568
 			while ($row = $result->fetch()) {
569
-				$row['etag'] = '"' . $row['etag'] . '"';
569
+				$row['etag'] = '"'.$row['etag'].'"';
570 570
 				$row['carddata'] = $this->readBlob($row['carddata']);
571 571
 				$cards[] = $row;
572 572
 			}
@@ -624,7 +624,7 @@  discard block
 block discarded – undo
624 624
 				'cardUri' => $cardUri,
625 625
 				'cardData' => $cardData]));
626 626
 
627
-		return '"' . $etag . '"';
627
+		return '"'.$etag.'"';
628 628
 	}
629 629
 
630 630
 	/**
@@ -674,7 +674,7 @@  discard block
 block discarded – undo
674 674
 				'cardUri' => $cardUri,
675 675
 				'cardData' => $cardData]));
676 676
 
677
-		return '"' . $etag . '"';
677
+		return '"'.$etag.'"';
678 678
 	}
679 679
 
680 680
 	/**
@@ -772,7 +772,7 @@  discard block
 block discarded – undo
772 772
 	function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null) {
773 773
 		// Current synctoken
774 774
 		$stmt = $this->db->prepare('SELECT `synctoken` FROM `*PREFIX*addressbooks` WHERE `id` = ?');
775
-		$stmt->execute([ $addressBookId ]);
775
+		$stmt->execute([$addressBookId]);
776 776
 		$currentToken = $stmt->fetchColumn(0);
777 777
 
778 778
 		if (is_null($currentToken)) return null;
@@ -787,8 +787,8 @@  discard block
 block discarded – undo
787 787
 		if ($syncToken) {
788 788
 
789 789
 			$query = "SELECT `uri`, `operation` FROM `*PREFIX*addressbookchanges` WHERE `synctoken` >= ? AND `synctoken` < ? AND `addressbookid` = ? ORDER BY `synctoken`";
790
-			if ($limit>0) {
791
-				$query .= " `LIMIT` " . (int)$limit;
790
+			if ($limit > 0) {
791
+				$query .= " `LIMIT` ".(int) $limit;
792 792
 			}
793 793
 
794 794
 			// Fetching all changes
@@ -799,15 +799,15 @@  discard block
 block discarded – undo
799 799
 
800 800
 			// This loop ensures that any duplicates are overwritten, only the
801 801
 			// last change on a node is relevant.
802
-			while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
802
+			while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
803 803
 
804 804
 				$changes[$row['uri']] = $row['operation'];
805 805
 
806 806
 			}
807 807
 
808
-			foreach($changes as $uri => $operation) {
808
+			foreach ($changes as $uri => $operation) {
809 809
 
810
-				switch($operation) {
810
+				switch ($operation) {
811 811
 					case 1:
812 812
 						$result['added'][] = $uri;
813 813
 						break;
@@ -893,7 +893,7 @@  discard block
 block discarded – undo
893 893
 
894 894
 		// No need for like when the pattern is empty
895 895
 		if ('' !== $pattern) {
896
-			$query2->andWhere($query2->expr()->ilike('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')));
896
+			$query2->andWhere($query2->expr()->ilike('cp.value', $query->createNamedParameter('%'.$this->db->escapeLikeParameter($pattern).'%')));
897 897
 		}
898 898
 
899 899
 		$query->select('c.carddata', 'c.uri')->from($this->dbCardsTable, 'c')
@@ -946,7 +946,7 @@  discard block
 block discarded – undo
946 946
 		$result->closeCursor();
947 947
 
948 948
 		if (!isset($uri['uri'])) {
949
-			throw new \InvalidArgumentException('Card does not exists: ' . $id);
949
+			throw new \InvalidArgumentException('Card does not exists: '.$id);
950 950
 		}
951 951
 
952 952
 		return $uri['uri'];
@@ -1018,11 +1018,11 @@  discard block
 block discarded – undo
1018 1018
 			);
1019 1019
 
1020 1020
 		foreach ($vCard->children() as $property) {
1021
-			if(!in_array($property->name, self::$indexProperties)) {
1021
+			if (!in_array($property->name, self::$indexProperties)) {
1022 1022
 				continue;
1023 1023
 			}
1024 1024
 			$preferred = 0;
1025
-			foreach($property->parameters as $parameter) {
1025
+			foreach ($property->parameters as $parameter) {
1026 1026
 				if ($parameter->name === 'TYPE' && strtoupper($parameter->getValue()) === 'PREF') {
1027 1027
 					$preferred = 1;
1028 1028
 					break;
@@ -1077,10 +1077,10 @@  discard block
 block discarded – undo
1077 1077
 		$result->closeCursor();
1078 1078
 
1079 1079
 		if (!isset($cardIds['id'])) {
1080
-			throw new \InvalidArgumentException('Card does not exists: ' . $uri);
1080
+			throw new \InvalidArgumentException('Card does not exists: '.$uri);
1081 1081
 		}
1082 1082
 
1083
-		return (int)$cardIds['id'];
1083
+		return (int) $cardIds['id'];
1084 1084
 	}
1085 1085
 
1086 1086
 	/**
@@ -1105,8 +1105,8 @@  discard block
 block discarded – undo
1105 1105
 	}
1106 1106
 
1107 1107
 	private function addOwnerPrincipal(&$addressbookInfo) {
1108
-		$ownerPrincipalKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal';
1109
-		$displaynameKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}owner-displayname';
1108
+		$ownerPrincipalKey = '{'.\OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD.'}owner-principal';
1109
+		$displaynameKey = '{'.\OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD.'}owner-displayname';
1110 1110
 		if (isset($addressbookInfo[$ownerPrincipalKey])) {
1111 1111
 			$uri = $addressbookInfo[$ownerPrincipalKey];
1112 1112
 		} else {
Please login to merge, or discard this patch.
Indentation   +1110 added lines, -1110 removed lines patch added patch discarded remove patch
@@ -53,1114 +53,1114 @@
 block discarded – undo
53 53
 
54 54
 class CardDavBackend implements BackendInterface, SyncSupport {
55 55
 
56
-	const PERSONAL_ADDRESSBOOK_URI = 'contacts';
57
-	const PERSONAL_ADDRESSBOOK_NAME = 'Contacts';
58
-
59
-	/** @var Principal */
60
-	private $principalBackend;
61
-
62
-	/** @var string */
63
-	private $dbCardsTable = 'cards';
64
-
65
-	/** @var string */
66
-	private $dbCardsPropertiesTable = 'cards_properties';
67
-
68
-	/** @var IDBConnection */
69
-	private $db;
70
-
71
-	/** @var Backend */
72
-	private $sharingBackend;
73
-
74
-	/** @var array properties to index */
75
-	public static $indexProperties = array(
76
-			'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME',
77
-			'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'CLOUD');
78
-
79
-	/**
80
-	 * @var string[] Map of uid => display name
81
-	 */
82
-	protected $userDisplayNames;
83
-
84
-	/** @var IUserManager */
85
-	private $userManager;
86
-
87
-	/** @var EventDispatcherInterface */
88
-	private $dispatcher;
89
-
90
-	/**
91
-	 * CardDavBackend constructor.
92
-	 *
93
-	 * @param IDBConnection $db
94
-	 * @param Principal $principalBackend
95
-	 * @param IUserManager $userManager
96
-	 * @param IGroupManager $groupManager
97
-	 * @param EventDispatcherInterface $dispatcher
98
-	 */
99
-	public function __construct(IDBConnection $db,
100
-								Principal $principalBackend,
101
-								IUserManager $userManager,
102
-								IGroupManager $groupManager,
103
-								EventDispatcherInterface $dispatcher) {
104
-		$this->db = $db;
105
-		$this->principalBackend = $principalBackend;
106
-		$this->userManager = $userManager;
107
-		$this->dispatcher = $dispatcher;
108
-		$this->sharingBackend = new Backend($this->db, $this->userManager, $groupManager, $principalBackend, 'addressbook');
109
-	}
110
-
111
-	/**
112
-	 * Return the number of address books for a principal
113
-	 *
114
-	 * @param $principalUri
115
-	 * @return int
116
-	 */
117
-	public function getAddressBooksForUserCount($principalUri) {
118
-		$principalUri = $this->convertPrincipal($principalUri, true);
119
-		$query = $this->db->getQueryBuilder();
120
-		$query->select($query->func()->count('*'))
121
-			->from('addressbooks')
122
-			->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
123
-
124
-		return (int)$query->execute()->fetchColumn();
125
-	}
126
-
127
-	/**
128
-	 * Returns the list of address books for a specific user.
129
-	 *
130
-	 * Every addressbook should have the following properties:
131
-	 *   id - an arbitrary unique id
132
-	 *   uri - the 'basename' part of the url
133
-	 *   principaluri - Same as the passed parameter
134
-	 *
135
-	 * Any additional clark-notation property may be passed besides this. Some
136
-	 * common ones are :
137
-	 *   {DAV:}displayname
138
-	 *   {urn:ietf:params:xml:ns:carddav}addressbook-description
139
-	 *   {http://calendarserver.org/ns/}getctag
140
-	 *
141
-	 * @param string $principalUri
142
-	 * @return array
143
-	 */
144
-	function getAddressBooksForUser($principalUri) {
145
-		$principalUriOriginal = $principalUri;
146
-		$principalUri = $this->convertPrincipal($principalUri, true);
147
-		$query = $this->db->getQueryBuilder();
148
-		$query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
149
-			->from('addressbooks')
150
-			->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
151
-
152
-		$addressBooks = [];
153
-
154
-		$result = $query->execute();
155
-		while($row = $result->fetch()) {
156
-			$addressBooks[$row['id']] = [
157
-				'id'  => $row['id'],
158
-				'uri' => $row['uri'],
159
-				'principaluri' => $this->convertPrincipal($row['principaluri'], false),
160
-				'{DAV:}displayname' => $row['displayname'],
161
-				'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
162
-				'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
163
-				'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
164
-			];
165
-
166
-			$this->addOwnerPrincipal($addressBooks[$row['id']]);
167
-		}
168
-		$result->closeCursor();
169
-
170
-		// query for shared calendars
171
-		$principals = $this->principalBackend->getGroupMembership($principalUriOriginal, true);
172
-		$principals = array_map(function($principal) {
173
-			return urldecode($principal);
174
-		}, $principals);
175
-		$principals[]= $principalUri;
176
-
177
-		$query = $this->db->getQueryBuilder();
178
-		$result = $query->select(['a.id', 'a.uri', 'a.displayname', 'a.principaluri', 'a.description', 'a.synctoken', 's.access'])
179
-			->from('dav_shares', 's')
180
-			->join('s', 'addressbooks', 'a', $query->expr()->eq('s.resourceid', 'a.id'))
181
-			->where($query->expr()->in('s.principaluri', $query->createParameter('principaluri')))
182
-			->andWhere($query->expr()->eq('s.type', $query->createParameter('type')))
183
-			->setParameter('type', 'addressbook')
184
-			->setParameter('principaluri', $principals, IQueryBuilder::PARAM_STR_ARRAY)
185
-			->execute();
186
-
187
-		$readOnlyPropertyName = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only';
188
-		while($row = $result->fetch()) {
189
-			if ($row['principaluri'] === $principalUri) {
190
-				continue;
191
-			}
192
-
193
-			$readOnly = (int) $row['access'] === Backend::ACCESS_READ;
194
-			if (isset($addressBooks[$row['id']])) {
195
-				if ($readOnly) {
196
-					// New share can not have more permissions then the old one.
197
-					continue;
198
-				}
199
-				if (isset($addressBooks[$row['id']][$readOnlyPropertyName]) &&
200
-					$addressBooks[$row['id']][$readOnlyPropertyName] === 0) {
201
-					// Old share is already read-write, no more permissions can be gained
202
-					continue;
203
-				}
204
-			}
205
-
206
-			list(, $name) = \Sabre\Uri\split($row['principaluri']);
207
-			$uri = $row['uri'] . '_shared_by_' . $name;
208
-			$displayName = $row['displayname'] . ' (' . $this->getUserDisplayName($name) . ')';
209
-
210
-			$addressBooks[$row['id']] = [
211
-				'id'  => $row['id'],
212
-				'uri' => $uri,
213
-				'principaluri' => $principalUriOriginal,
214
-				'{DAV:}displayname' => $displayName,
215
-				'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
216
-				'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
217
-				'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
218
-				'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'],
219
-				$readOnlyPropertyName => $readOnly,
220
-			];
221
-
222
-			$this->addOwnerPrincipal($addressBooks[$row['id']]);
223
-		}
224
-		$result->closeCursor();
225
-
226
-		return array_values($addressBooks);
227
-	}
228
-
229
-	public function getUsersOwnAddressBooks($principalUri) {
230
-		$principalUri = $this->convertPrincipal($principalUri, true);
231
-		$query = $this->db->getQueryBuilder();
232
-		$query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
233
-			  ->from('addressbooks')
234
-			  ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
235
-
236
-		$addressBooks = [];
237
-
238
-		$result = $query->execute();
239
-		while($row = $result->fetch()) {
240
-			$addressBooks[$row['id']] = [
241
-				'id'  => $row['id'],
242
-				'uri' => $row['uri'],
243
-				'principaluri' => $this->convertPrincipal($row['principaluri'], false),
244
-				'{DAV:}displayname' => $row['displayname'],
245
-				'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
246
-				'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
247
-				'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
248
-			];
249
-
250
-			$this->addOwnerPrincipal($addressBooks[$row['id']]);
251
-		}
252
-		$result->closeCursor();
253
-
254
-		return array_values($addressBooks);
255
-	}
256
-
257
-	private function getUserDisplayName($uid) {
258
-		if (!isset($this->userDisplayNames[$uid])) {
259
-			$user = $this->userManager->get($uid);
260
-
261
-			if ($user instanceof IUser) {
262
-				$this->userDisplayNames[$uid] = $user->getDisplayName();
263
-			} else {
264
-				$this->userDisplayNames[$uid] = $uid;
265
-			}
266
-		}
267
-
268
-		return $this->userDisplayNames[$uid];
269
-	}
270
-
271
-	/**
272
-	 * @param int $addressBookId
273
-	 */
274
-	public function getAddressBookById($addressBookId) {
275
-		$query = $this->db->getQueryBuilder();
276
-		$result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
277
-			->from('addressbooks')
278
-			->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
279
-			->execute();
280
-
281
-		$row = $result->fetch();
282
-		$result->closeCursor();
283
-		if ($row === false) {
284
-			return null;
285
-		}
286
-
287
-		$addressBook = [
288
-			'id'  => $row['id'],
289
-			'uri' => $row['uri'],
290
-			'principaluri' => $row['principaluri'],
291
-			'{DAV:}displayname' => $row['displayname'],
292
-			'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
293
-			'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
294
-			'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
295
-		];
296
-
297
-		$this->addOwnerPrincipal($addressBook);
298
-
299
-		return $addressBook;
300
-	}
301
-
302
-	/**
303
-	 * @param $addressBookUri
304
-	 * @return array|null
305
-	 */
306
-	public function getAddressBooksByUri($principal, $addressBookUri) {
307
-		$query = $this->db->getQueryBuilder();
308
-		$result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
309
-			->from('addressbooks')
310
-			->where($query->expr()->eq('uri', $query->createNamedParameter($addressBookUri)))
311
-			->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($principal)))
312
-			->setMaxResults(1)
313
-			->execute();
314
-
315
-		$row = $result->fetch();
316
-		$result->closeCursor();
317
-		if ($row === false) {
318
-			return null;
319
-		}
320
-
321
-		$addressBook = [
322
-			'id'  => $row['id'],
323
-			'uri' => $row['uri'],
324
-			'principaluri' => $row['principaluri'],
325
-			'{DAV:}displayname' => $row['displayname'],
326
-			'{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
327
-			'{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
328
-			'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
329
-		];
330
-
331
-		$this->addOwnerPrincipal($addressBook);
332
-
333
-		return $addressBook;
334
-	}
335
-
336
-	/**
337
-	 * Updates properties for an address book.
338
-	 *
339
-	 * The list of mutations is stored in a Sabre\DAV\PropPatch object.
340
-	 * To do the actual updates, you must tell this object which properties
341
-	 * you're going to process with the handle() method.
342
-	 *
343
-	 * Calling the handle method is like telling the PropPatch object "I
344
-	 * promise I can handle updating this property".
345
-	 *
346
-	 * Read the PropPatch documentation for more info and examples.
347
-	 *
348
-	 * @param string $addressBookId
349
-	 * @param \Sabre\DAV\PropPatch $propPatch
350
-	 * @return void
351
-	 */
352
-	function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch) {
353
-		$supportedProperties = [
354
-			'{DAV:}displayname',
355
-			'{' . Plugin::NS_CARDDAV . '}addressbook-description',
356
-		];
357
-
358
-		/**
359
-		 * @suppress SqlInjectionChecker
360
-		 */
361
-		$propPatch->handle($supportedProperties, function($mutations) use ($addressBookId) {
362
-
363
-			$updates = [];
364
-			foreach($mutations as $property=>$newValue) {
365
-
366
-				switch($property) {
367
-					case '{DAV:}displayname' :
368
-						$updates['displayname'] = $newValue;
369
-						break;
370
-					case '{' . Plugin::NS_CARDDAV . '}addressbook-description' :
371
-						$updates['description'] = $newValue;
372
-						break;
373
-				}
374
-			}
375
-			$query = $this->db->getQueryBuilder();
376
-			$query->update('addressbooks');
377
-
378
-			foreach($updates as $key=>$value) {
379
-				$query->set($key, $query->createNamedParameter($value));
380
-			}
381
-			$query->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
382
-			->execute();
383
-
384
-			$this->addChange($addressBookId, "", 2);
385
-
386
-			return true;
387
-
388
-		});
389
-	}
390
-
391
-	/**
392
-	 * Creates a new address book
393
-	 *
394
-	 * @param string $principalUri
395
-	 * @param string $url Just the 'basename' of the url.
396
-	 * @param array $properties
397
-	 * @return int
398
-	 * @throws BadRequest
399
-	 */
400
-	function createAddressBook($principalUri, $url, array $properties) {
401
-		$values = [
402
-			'displayname' => null,
403
-			'description' => null,
404
-			'principaluri' => $principalUri,
405
-			'uri' => $url,
406
-			'synctoken' => 1
407
-		];
408
-
409
-		foreach($properties as $property=>$newValue) {
410
-
411
-			switch($property) {
412
-				case '{DAV:}displayname' :
413
-					$values['displayname'] = $newValue;
414
-					break;
415
-				case '{' . Plugin::NS_CARDDAV . '}addressbook-description' :
416
-					$values['description'] = $newValue;
417
-					break;
418
-				default :
419
-					throw new BadRequest('Unknown property: ' . $property);
420
-			}
421
-
422
-		}
423
-
424
-		// Fallback to make sure the displayname is set. Some clients may refuse
425
-		// to work with addressbooks not having a displayname.
426
-		if(is_null($values['displayname'])) {
427
-			$values['displayname'] = $url;
428
-		}
429
-
430
-		$query = $this->db->getQueryBuilder();
431
-		$query->insert('addressbooks')
432
-			->values([
433
-				'uri' => $query->createParameter('uri'),
434
-				'displayname' => $query->createParameter('displayname'),
435
-				'description' => $query->createParameter('description'),
436
-				'principaluri' => $query->createParameter('principaluri'),
437
-				'synctoken' => $query->createParameter('synctoken'),
438
-			])
439
-			->setParameters($values)
440
-			->execute();
441
-
442
-		return $query->getLastInsertId();
443
-	}
444
-
445
-	/**
446
-	 * Deletes an entire addressbook and all its contents
447
-	 *
448
-	 * @param mixed $addressBookId
449
-	 * @return void
450
-	 */
451
-	function deleteAddressBook($addressBookId) {
452
-		$query = $this->db->getQueryBuilder();
453
-		$query->delete('cards')
454
-			->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
455
-			->setParameter('addressbookid', $addressBookId)
456
-			->execute();
457
-
458
-		$query->delete('addressbookchanges')
459
-			->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
460
-			->setParameter('addressbookid', $addressBookId)
461
-			->execute();
462
-
463
-		$query->delete('addressbooks')
464
-			->where($query->expr()->eq('id', $query->createParameter('id')))
465
-			->setParameter('id', $addressBookId)
466
-			->execute();
467
-
468
-		$this->sharingBackend->deleteAllShares($addressBookId);
469
-
470
-		$query->delete($this->dbCardsPropertiesTable)
471
-			->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
472
-			->execute();
473
-
474
-	}
475
-
476
-	/**
477
-	 * Returns all cards for a specific addressbook id.
478
-	 *
479
-	 * This method should return the following properties for each card:
480
-	 *   * carddata - raw vcard data
481
-	 *   * uri - Some unique url
482
-	 *   * lastmodified - A unix timestamp
483
-	 *
484
-	 * It's recommended to also return the following properties:
485
-	 *   * etag - A unique etag. This must change every time the card changes.
486
-	 *   * size - The size of the card in bytes.
487
-	 *
488
-	 * If these last two properties are provided, less time will be spent
489
-	 * calculating them. If they are specified, you can also ommit carddata.
490
-	 * This may speed up certain requests, especially with large cards.
491
-	 *
492
-	 * @param mixed $addressBookId
493
-	 * @return array
494
-	 */
495
-	function getCards($addressBookId) {
496
-		$query = $this->db->getQueryBuilder();
497
-		$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
498
-			->from('cards')
499
-			->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
500
-
501
-		$cards = [];
502
-
503
-		$result = $query->execute();
504
-		while($row = $result->fetch()) {
505
-			$row['etag'] = '"' . $row['etag'] . '"';
506
-			$row['carddata'] = $this->readBlob($row['carddata']);
507
-			$cards[] = $row;
508
-		}
509
-		$result->closeCursor();
510
-
511
-		return $cards;
512
-	}
513
-
514
-	/**
515
-	 * Returns a specific card.
516
-	 *
517
-	 * The same set of properties must be returned as with getCards. The only
518
-	 * exception is that 'carddata' is absolutely required.
519
-	 *
520
-	 * If the card does not exist, you must return false.
521
-	 *
522
-	 * @param mixed $addressBookId
523
-	 * @param string $cardUri
524
-	 * @return array
525
-	 */
526
-	function getCard($addressBookId, $cardUri) {
527
-		$query = $this->db->getQueryBuilder();
528
-		$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
529
-			->from('cards')
530
-			->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
531
-			->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
532
-			->setMaxResults(1);
533
-
534
-		$result = $query->execute();
535
-		$row = $result->fetch();
536
-		if (!$row) {
537
-			return false;
538
-		}
539
-		$row['etag'] = '"' . $row['etag'] . '"';
540
-		$row['carddata'] = $this->readBlob($row['carddata']);
541
-
542
-		return $row;
543
-	}
544
-
545
-	/**
546
-	 * Returns a list of cards.
547
-	 *
548
-	 * This method should work identical to getCard, but instead return all the
549
-	 * cards in the list as an array.
550
-	 *
551
-	 * If the backend supports this, it may allow for some speed-ups.
552
-	 *
553
-	 * @param mixed $addressBookId
554
-	 * @param string[] $uris
555
-	 * @return array
556
-	 */
557
-	function getMultipleCards($addressBookId, array $uris) {
558
-		if (empty($uris)) {
559
-			return [];
560
-		}
561
-
562
-		$chunks = array_chunk($uris, 100);
563
-		$cards = [];
564
-
565
-		$query = $this->db->getQueryBuilder();
566
-		$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
567
-			->from('cards')
568
-			->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
569
-			->andWhere($query->expr()->in('uri', $query->createParameter('uri')));
570
-
571
-		foreach ($chunks as $uris) {
572
-			$query->setParameter('uri', $uris, IQueryBuilder::PARAM_STR_ARRAY);
573
-			$result = $query->execute();
574
-
575
-			while ($row = $result->fetch()) {
576
-				$row['etag'] = '"' . $row['etag'] . '"';
577
-				$row['carddata'] = $this->readBlob($row['carddata']);
578
-				$cards[] = $row;
579
-			}
580
-			$result->closeCursor();
581
-		}
582
-		return $cards;
583
-	}
584
-
585
-	/**
586
-	 * Creates a new card.
587
-	 *
588
-	 * The addressbook id will be passed as the first argument. This is the
589
-	 * same id as it is returned from the getAddressBooksForUser method.
590
-	 *
591
-	 * The cardUri is a base uri, and doesn't include the full path. The
592
-	 * cardData argument is the vcard body, and is passed as a string.
593
-	 *
594
-	 * It is possible to return an ETag from this method. This ETag is for the
595
-	 * newly created resource, and must be enclosed with double quotes (that
596
-	 * is, the string itself must contain the double quotes).
597
-	 *
598
-	 * You should only return the ETag if you store the carddata as-is. If a
599
-	 * subsequent GET request on the same card does not have the same body,
600
-	 * byte-by-byte and you did return an ETag here, clients tend to get
601
-	 * confused.
602
-	 *
603
-	 * If you don't return an ETag, you can just return null.
604
-	 *
605
-	 * @param mixed $addressBookId
606
-	 * @param string $cardUri
607
-	 * @param string $cardData
608
-	 * @return string
609
-	 */
610
-	function createCard($addressBookId, $cardUri, $cardData) {
611
-		$etag = md5($cardData);
612
-		$uid = $this->getUID($cardData);
613
-
614
-		$q = $this->db->getQueryBuilder();
615
-		$q->select('uid')
616
-			->from('cards')
617
-			->where($q->expr()->eq('addressbookid', $q->createNamedParameter($addressBookId)))
618
-			->andWhere($q->expr()->eq('uid', $q->createNamedParameter($uid)))
619
-			->setMaxResults(1);
620
-		$result = $q->execute();
621
-		$count = (bool) $result->fetchColumn();
622
-		$result->closeCursor();
623
-		if ($count) {
624
-			throw new \Sabre\DAV\Exception\BadRequest('VCard object with uid already exists in this addressbook collection.');
625
-		}
626
-
627
-		$query = $this->db->getQueryBuilder();
628
-		$query->insert('cards')
629
-			->values([
630
-				'carddata' => $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB),
631
-				'uri' => $query->createNamedParameter($cardUri),
632
-				'lastmodified' => $query->createNamedParameter(time()),
633
-				'addressbookid' => $query->createNamedParameter($addressBookId),
634
-				'size' => $query->createNamedParameter(strlen($cardData)),
635
-				'etag' => $query->createNamedParameter($etag),
636
-				'uid' => $query->createNamedParameter($uid),
637
-			])
638
-			->execute();
639
-
640
-		$this->addChange($addressBookId, $cardUri, 1);
641
-		$this->updateProperties($addressBookId, $cardUri, $cardData);
642
-
643
-		$this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::createCard',
644
-			new GenericEvent(null, [
645
-				'addressBookId' => $addressBookId,
646
-				'cardUri' => $cardUri,
647
-				'cardData' => $cardData]));
648
-
649
-		return '"' . $etag . '"';
650
-	}
651
-
652
-	/**
653
-	 * Updates a card.
654
-	 *
655
-	 * The addressbook id will be passed as the first argument. This is the
656
-	 * same id as it is returned from the getAddressBooksForUser method.
657
-	 *
658
-	 * The cardUri is a base uri, and doesn't include the full path. The
659
-	 * cardData argument is the vcard body, and is passed as a string.
660
-	 *
661
-	 * It is possible to return an ETag from this method. This ETag should
662
-	 * match that of the updated resource, and must be enclosed with double
663
-	 * quotes (that is: the string itself must contain the actual quotes).
664
-	 *
665
-	 * You should only return the ETag if you store the carddata as-is. If a
666
-	 * subsequent GET request on the same card does not have the same body,
667
-	 * byte-by-byte and you did return an ETag here, clients tend to get
668
-	 * confused.
669
-	 *
670
-	 * If you don't return an ETag, you can just return null.
671
-	 *
672
-	 * @param mixed $addressBookId
673
-	 * @param string $cardUri
674
-	 * @param string $cardData
675
-	 * @return string
676
-	 */
677
-	function updateCard($addressBookId, $cardUri, $cardData) {
678
-
679
-		$uid = $this->getUID($cardData);
680
-		$etag = md5($cardData);
681
-		$query = $this->db->getQueryBuilder();
682
-		$query->update('cards')
683
-			->set('carddata', $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB))
684
-			->set('lastmodified', $query->createNamedParameter(time()))
685
-			->set('size', $query->createNamedParameter(strlen($cardData)))
686
-			->set('etag', $query->createNamedParameter($etag))
687
-			->set('uid', $query->createNamedParameter($uid))
688
-			->where($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
689
-			->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
690
-			->execute();
691
-
692
-		$this->addChange($addressBookId, $cardUri, 2);
693
-		$this->updateProperties($addressBookId, $cardUri, $cardData);
694
-
695
-		$this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::updateCard',
696
-			new GenericEvent(null, [
697
-				'addressBookId' => $addressBookId,
698
-				'cardUri' => $cardUri,
699
-				'cardData' => $cardData]));
700
-
701
-		return '"' . $etag . '"';
702
-	}
703
-
704
-	/**
705
-	 * Deletes a card
706
-	 *
707
-	 * @param mixed $addressBookId
708
-	 * @param string $cardUri
709
-	 * @return bool
710
-	 */
711
-	function deleteCard($addressBookId, $cardUri) {
712
-		try {
713
-			$cardId = $this->getCardId($addressBookId, $cardUri);
714
-		} catch (\InvalidArgumentException $e) {
715
-			$cardId = null;
716
-		}
717
-		$query = $this->db->getQueryBuilder();
718
-		$ret = $query->delete('cards')
719
-			->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
720
-			->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
721
-			->execute();
722
-
723
-		$this->addChange($addressBookId, $cardUri, 3);
724
-
725
-		$this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::deleteCard',
726
-			new GenericEvent(null, [
727
-				'addressBookId' => $addressBookId,
728
-				'cardUri' => $cardUri]));
729
-
730
-		if ($ret === 1) {
731
-			if ($cardId !== null) {
732
-				$this->purgeProperties($addressBookId, $cardId);
733
-			}
734
-			return true;
735
-		}
736
-
737
-		return false;
738
-	}
739
-
740
-	/**
741
-	 * The getChanges method returns all the changes that have happened, since
742
-	 * the specified syncToken in the specified address book.
743
-	 *
744
-	 * This function should return an array, such as the following:
745
-	 *
746
-	 * [
747
-	 *   'syncToken' => 'The current synctoken',
748
-	 *   'added'   => [
749
-	 *      'new.txt',
750
-	 *   ],
751
-	 *   'modified'   => [
752
-	 *      'modified.txt',
753
-	 *   ],
754
-	 *   'deleted' => [
755
-	 *      'foo.php.bak',
756
-	 *      'old.txt'
757
-	 *   ]
758
-	 * ];
759
-	 *
760
-	 * The returned syncToken property should reflect the *current* syncToken
761
-	 * of the calendar, as reported in the {http://sabredav.org/ns}sync-token
762
-	 * property. This is needed here too, to ensure the operation is atomic.
763
-	 *
764
-	 * If the $syncToken argument is specified as null, this is an initial
765
-	 * sync, and all members should be reported.
766
-	 *
767
-	 * The modified property is an array of nodenames that have changed since
768
-	 * the last token.
769
-	 *
770
-	 * The deleted property is an array with nodenames, that have been deleted
771
-	 * from collection.
772
-	 *
773
-	 * The $syncLevel argument is basically the 'depth' of the report. If it's
774
-	 * 1, you only have to report changes that happened only directly in
775
-	 * immediate descendants. If it's 2, it should also include changes from
776
-	 * the nodes below the child collections. (grandchildren)
777
-	 *
778
-	 * The $limit argument allows a client to specify how many results should
779
-	 * be returned at most. If the limit is not specified, it should be treated
780
-	 * as infinite.
781
-	 *
782
-	 * If the limit (infinite or not) is higher than you're willing to return,
783
-	 * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
784
-	 *
785
-	 * If the syncToken is expired (due to data cleanup) or unknown, you must
786
-	 * return null.
787
-	 *
788
-	 * The limit is 'suggestive'. You are free to ignore it.
789
-	 *
790
-	 * @param string $addressBookId
791
-	 * @param string $syncToken
792
-	 * @param int $syncLevel
793
-	 * @param int $limit
794
-	 * @return array
795
-	 */
796
-	function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null) {
797
-		// Current synctoken
798
-		$stmt = $this->db->prepare('SELECT `synctoken` FROM `*PREFIX*addressbooks` WHERE `id` = ?');
799
-		$stmt->execute([ $addressBookId ]);
800
-		$currentToken = $stmt->fetchColumn(0);
801
-
802
-		if (is_null($currentToken)) return null;
803
-
804
-		$result = [
805
-			'syncToken' => $currentToken,
806
-			'added'     => [],
807
-			'modified'  => [],
808
-			'deleted'   => [],
809
-		];
810
-
811
-		if ($syncToken) {
812
-
813
-			$query = "SELECT `uri`, `operation` FROM `*PREFIX*addressbookchanges` WHERE `synctoken` >= ? AND `synctoken` < ? AND `addressbookid` = ? ORDER BY `synctoken`";
814
-			if ($limit>0) {
815
-				$query .= " `LIMIT` " . (int)$limit;
816
-			}
817
-
818
-			// Fetching all changes
819
-			$stmt = $this->db->prepare($query);
820
-			$stmt->execute([$syncToken, $currentToken, $addressBookId]);
821
-
822
-			$changes = [];
823
-
824
-			// This loop ensures that any duplicates are overwritten, only the
825
-			// last change on a node is relevant.
826
-			while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
827
-
828
-				$changes[$row['uri']] = $row['operation'];
829
-
830
-			}
831
-
832
-			foreach($changes as $uri => $operation) {
833
-
834
-				switch($operation) {
835
-					case 1:
836
-						$result['added'][] = $uri;
837
-						break;
838
-					case 2:
839
-						$result['modified'][] = $uri;
840
-						break;
841
-					case 3:
842
-						$result['deleted'][] = $uri;
843
-						break;
844
-				}
845
-
846
-			}
847
-		} else {
848
-			// No synctoken supplied, this is the initial sync.
849
-			$query = "SELECT `uri` FROM `*PREFIX*cards` WHERE `addressbookid` = ?";
850
-			$stmt = $this->db->prepare($query);
851
-			$stmt->execute([$addressBookId]);
852
-
853
-			$result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN);
854
-		}
855
-		return $result;
856
-	}
857
-
858
-	/**
859
-	 * Adds a change record to the addressbookchanges table.
860
-	 *
861
-	 * @param mixed $addressBookId
862
-	 * @param string $objectUri
863
-	 * @param int $operation 1 = add, 2 = modify, 3 = delete
864
-	 * @return void
865
-	 */
866
-	protected function addChange($addressBookId, $objectUri, $operation) {
867
-		$sql = 'INSERT INTO `*PREFIX*addressbookchanges`(`uri`, `synctoken`, `addressbookid`, `operation`) SELECT ?, `synctoken`, ?, ? FROM `*PREFIX*addressbooks` WHERE `id` = ?';
868
-		$stmt = $this->db->prepare($sql);
869
-		$stmt->execute([
870
-			$objectUri,
871
-			$addressBookId,
872
-			$operation,
873
-			$addressBookId
874
-		]);
875
-		$stmt = $this->db->prepare('UPDATE `*PREFIX*addressbooks` SET `synctoken` = `synctoken` + 1 WHERE `id` = ?');
876
-		$stmt->execute([
877
-			$addressBookId
878
-		]);
879
-	}
880
-
881
-	private function readBlob($cardData) {
882
-		if (is_resource($cardData)) {
883
-			return stream_get_contents($cardData);
884
-		}
885
-
886
-		return $cardData;
887
-	}
888
-
889
-	/**
890
-	 * @param IShareable $shareable
891
-	 * @param string[] $add
892
-	 * @param string[] $remove
893
-	 */
894
-	public function updateShares(IShareable $shareable, $add, $remove) {
895
-		$this->sharingBackend->updateShares($shareable, $add, $remove);
896
-	}
897
-
898
-	/**
899
-	 * search contact
900
-	 *
901
-	 * @param int $addressBookId
902
-	 * @param string $pattern which should match within the $searchProperties
903
-	 * @param array $searchProperties defines the properties within the query pattern should match
904
-	 * @return array an array of contacts which are arrays of key-value-pairs
905
-	 */
906
-	public function search($addressBookId, $pattern, $searchProperties) {
907
-		$query = $this->db->getQueryBuilder();
908
-		$query2 = $this->db->getQueryBuilder();
909
-
910
-		$query2->selectDistinct('cp.cardid')->from($this->dbCardsPropertiesTable, 'cp');
911
-		$query2->andWhere($query2->expr()->eq('cp.addressbookid', $query->createNamedParameter($addressBookId)));
912
-		$or = $query2->expr()->orX();
913
-		foreach ($searchProperties as $property) {
914
-			$or->add($query2->expr()->eq('cp.name', $query->createNamedParameter($property)));
915
-		}
916
-		$query2->andWhere($or);
917
-
918
-		// No need for like when the pattern is empty
919
-		if ('' !== $pattern) {
920
-			$query2->andWhere($query2->expr()->ilike('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')));
921
-		}
922
-
923
-		$query->select('c.carddata', 'c.uri')->from($this->dbCardsTable, 'c')
924
-			->where($query->expr()->in('c.id', $query->createFunction($query2->getSQL())));
925
-
926
-		$result = $query->execute();
927
-		$cards = $result->fetchAll();
928
-
929
-		$result->closeCursor();
930
-
931
-		return array_map(function($array) {
932
-			$array['carddata'] = $this->readBlob($array['carddata']);
933
-			return $array;
934
-		}, $cards);
935
-	}
936
-
937
-	/**
938
-	 * @param int $bookId
939
-	 * @param string $name
940
-	 * @return array
941
-	 */
942
-	public function collectCardProperties($bookId, $name) {
943
-		$query = $this->db->getQueryBuilder();
944
-		$result = $query->selectDistinct('value')
945
-			->from($this->dbCardsPropertiesTable)
946
-			->where($query->expr()->eq('name', $query->createNamedParameter($name)))
947
-			->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($bookId)))
948
-			->execute();
949
-
950
-		$all = $result->fetchAll(PDO::FETCH_COLUMN);
951
-		$result->closeCursor();
952
-
953
-		return $all;
954
-	}
955
-
956
-	/**
957
-	 * get URI from a given contact
958
-	 *
959
-	 * @param int $id
960
-	 * @return string
961
-	 */
962
-	public function getCardUri($id) {
963
-		$query = $this->db->getQueryBuilder();
964
-		$query->select('uri')->from($this->dbCardsTable)
965
-				->where($query->expr()->eq('id', $query->createParameter('id')))
966
-				->setParameter('id', $id);
967
-
968
-		$result = $query->execute();
969
-		$uri = $result->fetch();
970
-		$result->closeCursor();
971
-
972
-		if (!isset($uri['uri'])) {
973
-			throw new \InvalidArgumentException('Card does not exists: ' . $id);
974
-		}
975
-
976
-		return $uri['uri'];
977
-	}
978
-
979
-	/**
980
-	 * return contact with the given URI
981
-	 *
982
-	 * @param int $addressBookId
983
-	 * @param string $uri
984
-	 * @returns array
985
-	 */
986
-	public function getContact($addressBookId, $uri) {
987
-		$result = [];
988
-		$query = $this->db->getQueryBuilder();
989
-		$query->select('*')->from($this->dbCardsTable)
990
-				->where($query->expr()->eq('uri', $query->createNamedParameter($uri)))
991
-				->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
992
-		$queryResult = $query->execute();
993
-		$contact = $queryResult->fetch();
994
-		$queryResult->closeCursor();
995
-
996
-		if (is_array($contact)) {
997
-			$result = $contact;
998
-		}
999
-
1000
-		return $result;
1001
-	}
1002
-
1003
-	/**
1004
-	 * Returns the list of people whom this address book is shared with.
1005
-	 *
1006
-	 * Every element in this array should have the following properties:
1007
-	 *   * href - Often a mailto: address
1008
-	 *   * commonName - Optional, for example a first + last name
1009
-	 *   * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
1010
-	 *   * readOnly - boolean
1011
-	 *   * summary - Optional, a description for the share
1012
-	 *
1013
-	 * @return array
1014
-	 */
1015
-	public function getShares($addressBookId) {
1016
-		return $this->sharingBackend->getShares($addressBookId);
1017
-	}
1018
-
1019
-	/**
1020
-	 * update properties table
1021
-	 *
1022
-	 * @param int $addressBookId
1023
-	 * @param string $cardUri
1024
-	 * @param string $vCardSerialized
1025
-	 */
1026
-	protected function updateProperties($addressBookId, $cardUri, $vCardSerialized) {
1027
-		$cardId = $this->getCardId($addressBookId, $cardUri);
1028
-		$vCard = $this->readCard($vCardSerialized);
1029
-
1030
-		$this->purgeProperties($addressBookId, $cardId);
1031
-
1032
-		$query = $this->db->getQueryBuilder();
1033
-		$query->insert($this->dbCardsPropertiesTable)
1034
-			->values(
1035
-				[
1036
-					'addressbookid' => $query->createNamedParameter($addressBookId),
1037
-					'cardid' => $query->createNamedParameter($cardId),
1038
-					'name' => $query->createParameter('name'),
1039
-					'value' => $query->createParameter('value'),
1040
-					'preferred' => $query->createParameter('preferred')
1041
-				]
1042
-			);
1043
-
1044
-		foreach ($vCard->children() as $property) {
1045
-			if(!in_array($property->name, self::$indexProperties)) {
1046
-				continue;
1047
-			}
1048
-			$preferred = 0;
1049
-			foreach($property->parameters as $parameter) {
1050
-				if ($parameter->name === 'TYPE' && strtoupper($parameter->getValue()) === 'PREF') {
1051
-					$preferred = 1;
1052
-					break;
1053
-				}
1054
-			}
1055
-			$query->setParameter('name', $property->name);
1056
-			$query->setParameter('value', substr($property->getValue(), 0, 254));
1057
-			$query->setParameter('preferred', $preferred);
1058
-			$query->execute();
1059
-		}
1060
-	}
1061
-
1062
-	/**
1063
-	 * read vCard data into a vCard object
1064
-	 *
1065
-	 * @param string $cardData
1066
-	 * @return VCard
1067
-	 */
1068
-	protected function readCard($cardData) {
1069
-		return  Reader::read($cardData);
1070
-	}
1071
-
1072
-	/**
1073
-	 * delete all properties from a given card
1074
-	 *
1075
-	 * @param int $addressBookId
1076
-	 * @param int $cardId
1077
-	 */
1078
-	protected function purgeProperties($addressBookId, $cardId) {
1079
-		$query = $this->db->getQueryBuilder();
1080
-		$query->delete($this->dbCardsPropertiesTable)
1081
-			->where($query->expr()->eq('cardid', $query->createNamedParameter($cardId)))
1082
-			->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
1083
-		$query->execute();
1084
-	}
1085
-
1086
-	/**
1087
-	 * get ID from a given contact
1088
-	 *
1089
-	 * @param int $addressBookId
1090
-	 * @param string $uri
1091
-	 * @return int
1092
-	 */
1093
-	protected function getCardId($addressBookId, $uri) {
1094
-		$query = $this->db->getQueryBuilder();
1095
-		$query->select('id')->from($this->dbCardsTable)
1096
-			->where($query->expr()->eq('uri', $query->createNamedParameter($uri)))
1097
-			->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
1098
-
1099
-		$result = $query->execute();
1100
-		$cardIds = $result->fetch();
1101
-		$result->closeCursor();
1102
-
1103
-		if (!isset($cardIds['id'])) {
1104
-			throw new \InvalidArgumentException('Card does not exists: ' . $uri);
1105
-		}
1106
-
1107
-		return (int)$cardIds['id'];
1108
-	}
1109
-
1110
-	/**
1111
-	 * For shared address books the sharee is set in the ACL of the address book
1112
-	 * @param $addressBookId
1113
-	 * @param $acl
1114
-	 * @return array
1115
-	 */
1116
-	public function applyShareAcl($addressBookId, $acl) {
1117
-		return $this->sharingBackend->applyShareAcl($addressBookId, $acl);
1118
-	}
1119
-
1120
-	private function convertPrincipal($principalUri, $toV2) {
1121
-		if ($this->principalBackend->getPrincipalPrefix() === 'principals') {
1122
-			list(, $name) = \Sabre\Uri\split($principalUri);
1123
-			if ($toV2 === true) {
1124
-				return "principals/users/$name";
1125
-			}
1126
-			return "principals/$name";
1127
-		}
1128
-		return $principalUri;
1129
-	}
1130
-
1131
-	private function addOwnerPrincipal(&$addressbookInfo) {
1132
-		$ownerPrincipalKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal';
1133
-		$displaynameKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}owner-displayname';
1134
-		if (isset($addressbookInfo[$ownerPrincipalKey])) {
1135
-			$uri = $addressbookInfo[$ownerPrincipalKey];
1136
-		} else {
1137
-			$uri = $addressbookInfo['principaluri'];
1138
-		}
1139
-
1140
-		$principalInformation = $this->principalBackend->getPrincipalByPath($uri);
1141
-		if (isset($principalInformation['{DAV:}displayname'])) {
1142
-			$addressbookInfo[$displaynameKey] = $principalInformation['{DAV:}displayname'];
1143
-		}
1144
-	}
1145
-
1146
-	/**
1147
-	 * Extract UID from vcard
1148
-	 *
1149
-	 * @param string $cardData the vcard raw data
1150
-	 * @return string the uid
1151
-	 * @throws BadRequest if no UID is available
1152
-	 */
1153
-	private function getUID($cardData) {
1154
-		if ($cardData != '') {
1155
-			$vCard = Reader::read($cardData);
1156
-			if ($vCard->UID) {
1157
-				$uid = $vCard->UID->getValue();
1158
-				return $uid;
1159
-			}
1160
-			// should already be handled, but just in case
1161
-			throw new BadRequest('vCards on CardDAV servers MUST have a UID property');
1162
-		}
1163
-		// should already be handled, but just in case
1164
-		throw new BadRequest('vCard can not be empty');
1165
-	}
56
+    const PERSONAL_ADDRESSBOOK_URI = 'contacts';
57
+    const PERSONAL_ADDRESSBOOK_NAME = 'Contacts';
58
+
59
+    /** @var Principal */
60
+    private $principalBackend;
61
+
62
+    /** @var string */
63
+    private $dbCardsTable = 'cards';
64
+
65
+    /** @var string */
66
+    private $dbCardsPropertiesTable = 'cards_properties';
67
+
68
+    /** @var IDBConnection */
69
+    private $db;
70
+
71
+    /** @var Backend */
72
+    private $sharingBackend;
73
+
74
+    /** @var array properties to index */
75
+    public static $indexProperties = array(
76
+            'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME',
77
+            'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'CLOUD');
78
+
79
+    /**
80
+     * @var string[] Map of uid => display name
81
+     */
82
+    protected $userDisplayNames;
83
+
84
+    /** @var IUserManager */
85
+    private $userManager;
86
+
87
+    /** @var EventDispatcherInterface */
88
+    private $dispatcher;
89
+
90
+    /**
91
+     * CardDavBackend constructor.
92
+     *
93
+     * @param IDBConnection $db
94
+     * @param Principal $principalBackend
95
+     * @param IUserManager $userManager
96
+     * @param IGroupManager $groupManager
97
+     * @param EventDispatcherInterface $dispatcher
98
+     */
99
+    public function __construct(IDBConnection $db,
100
+                                Principal $principalBackend,
101
+                                IUserManager $userManager,
102
+                                IGroupManager $groupManager,
103
+                                EventDispatcherInterface $dispatcher) {
104
+        $this->db = $db;
105
+        $this->principalBackend = $principalBackend;
106
+        $this->userManager = $userManager;
107
+        $this->dispatcher = $dispatcher;
108
+        $this->sharingBackend = new Backend($this->db, $this->userManager, $groupManager, $principalBackend, 'addressbook');
109
+    }
110
+
111
+    /**
112
+     * Return the number of address books for a principal
113
+     *
114
+     * @param $principalUri
115
+     * @return int
116
+     */
117
+    public function getAddressBooksForUserCount($principalUri) {
118
+        $principalUri = $this->convertPrincipal($principalUri, true);
119
+        $query = $this->db->getQueryBuilder();
120
+        $query->select($query->func()->count('*'))
121
+            ->from('addressbooks')
122
+            ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
123
+
124
+        return (int)$query->execute()->fetchColumn();
125
+    }
126
+
127
+    /**
128
+     * Returns the list of address books for a specific user.
129
+     *
130
+     * Every addressbook should have the following properties:
131
+     *   id - an arbitrary unique id
132
+     *   uri - the 'basename' part of the url
133
+     *   principaluri - Same as the passed parameter
134
+     *
135
+     * Any additional clark-notation property may be passed besides this. Some
136
+     * common ones are :
137
+     *   {DAV:}displayname
138
+     *   {urn:ietf:params:xml:ns:carddav}addressbook-description
139
+     *   {http://calendarserver.org/ns/}getctag
140
+     *
141
+     * @param string $principalUri
142
+     * @return array
143
+     */
144
+    function getAddressBooksForUser($principalUri) {
145
+        $principalUriOriginal = $principalUri;
146
+        $principalUri = $this->convertPrincipal($principalUri, true);
147
+        $query = $this->db->getQueryBuilder();
148
+        $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
149
+            ->from('addressbooks')
150
+            ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
151
+
152
+        $addressBooks = [];
153
+
154
+        $result = $query->execute();
155
+        while($row = $result->fetch()) {
156
+            $addressBooks[$row['id']] = [
157
+                'id'  => $row['id'],
158
+                'uri' => $row['uri'],
159
+                'principaluri' => $this->convertPrincipal($row['principaluri'], false),
160
+                '{DAV:}displayname' => $row['displayname'],
161
+                '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
162
+                '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
163
+                '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
164
+            ];
165
+
166
+            $this->addOwnerPrincipal($addressBooks[$row['id']]);
167
+        }
168
+        $result->closeCursor();
169
+
170
+        // query for shared calendars
171
+        $principals = $this->principalBackend->getGroupMembership($principalUriOriginal, true);
172
+        $principals = array_map(function($principal) {
173
+            return urldecode($principal);
174
+        }, $principals);
175
+        $principals[]= $principalUri;
176
+
177
+        $query = $this->db->getQueryBuilder();
178
+        $result = $query->select(['a.id', 'a.uri', 'a.displayname', 'a.principaluri', 'a.description', 'a.synctoken', 's.access'])
179
+            ->from('dav_shares', 's')
180
+            ->join('s', 'addressbooks', 'a', $query->expr()->eq('s.resourceid', 'a.id'))
181
+            ->where($query->expr()->in('s.principaluri', $query->createParameter('principaluri')))
182
+            ->andWhere($query->expr()->eq('s.type', $query->createParameter('type')))
183
+            ->setParameter('type', 'addressbook')
184
+            ->setParameter('principaluri', $principals, IQueryBuilder::PARAM_STR_ARRAY)
185
+            ->execute();
186
+
187
+        $readOnlyPropertyName = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only';
188
+        while($row = $result->fetch()) {
189
+            if ($row['principaluri'] === $principalUri) {
190
+                continue;
191
+            }
192
+
193
+            $readOnly = (int) $row['access'] === Backend::ACCESS_READ;
194
+            if (isset($addressBooks[$row['id']])) {
195
+                if ($readOnly) {
196
+                    // New share can not have more permissions then the old one.
197
+                    continue;
198
+                }
199
+                if (isset($addressBooks[$row['id']][$readOnlyPropertyName]) &&
200
+                    $addressBooks[$row['id']][$readOnlyPropertyName] === 0) {
201
+                    // Old share is already read-write, no more permissions can be gained
202
+                    continue;
203
+                }
204
+            }
205
+
206
+            list(, $name) = \Sabre\Uri\split($row['principaluri']);
207
+            $uri = $row['uri'] . '_shared_by_' . $name;
208
+            $displayName = $row['displayname'] . ' (' . $this->getUserDisplayName($name) . ')';
209
+
210
+            $addressBooks[$row['id']] = [
211
+                'id'  => $row['id'],
212
+                'uri' => $uri,
213
+                'principaluri' => $principalUriOriginal,
214
+                '{DAV:}displayname' => $displayName,
215
+                '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
216
+                '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
217
+                '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
218
+                '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'],
219
+                $readOnlyPropertyName => $readOnly,
220
+            ];
221
+
222
+            $this->addOwnerPrincipal($addressBooks[$row['id']]);
223
+        }
224
+        $result->closeCursor();
225
+
226
+        return array_values($addressBooks);
227
+    }
228
+
229
+    public function getUsersOwnAddressBooks($principalUri) {
230
+        $principalUri = $this->convertPrincipal($principalUri, true);
231
+        $query = $this->db->getQueryBuilder();
232
+        $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
233
+                ->from('addressbooks')
234
+                ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
235
+
236
+        $addressBooks = [];
237
+
238
+        $result = $query->execute();
239
+        while($row = $result->fetch()) {
240
+            $addressBooks[$row['id']] = [
241
+                'id'  => $row['id'],
242
+                'uri' => $row['uri'],
243
+                'principaluri' => $this->convertPrincipal($row['principaluri'], false),
244
+                '{DAV:}displayname' => $row['displayname'],
245
+                '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
246
+                '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
247
+                '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
248
+            ];
249
+
250
+            $this->addOwnerPrincipal($addressBooks[$row['id']]);
251
+        }
252
+        $result->closeCursor();
253
+
254
+        return array_values($addressBooks);
255
+    }
256
+
257
+    private function getUserDisplayName($uid) {
258
+        if (!isset($this->userDisplayNames[$uid])) {
259
+            $user = $this->userManager->get($uid);
260
+
261
+            if ($user instanceof IUser) {
262
+                $this->userDisplayNames[$uid] = $user->getDisplayName();
263
+            } else {
264
+                $this->userDisplayNames[$uid] = $uid;
265
+            }
266
+        }
267
+
268
+        return $this->userDisplayNames[$uid];
269
+    }
270
+
271
+    /**
272
+     * @param int $addressBookId
273
+     */
274
+    public function getAddressBookById($addressBookId) {
275
+        $query = $this->db->getQueryBuilder();
276
+        $result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
277
+            ->from('addressbooks')
278
+            ->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
279
+            ->execute();
280
+
281
+        $row = $result->fetch();
282
+        $result->closeCursor();
283
+        if ($row === false) {
284
+            return null;
285
+        }
286
+
287
+        $addressBook = [
288
+            'id'  => $row['id'],
289
+            'uri' => $row['uri'],
290
+            'principaluri' => $row['principaluri'],
291
+            '{DAV:}displayname' => $row['displayname'],
292
+            '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
293
+            '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
294
+            '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
295
+        ];
296
+
297
+        $this->addOwnerPrincipal($addressBook);
298
+
299
+        return $addressBook;
300
+    }
301
+
302
+    /**
303
+     * @param $addressBookUri
304
+     * @return array|null
305
+     */
306
+    public function getAddressBooksByUri($principal, $addressBookUri) {
307
+        $query = $this->db->getQueryBuilder();
308
+        $result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
309
+            ->from('addressbooks')
310
+            ->where($query->expr()->eq('uri', $query->createNamedParameter($addressBookUri)))
311
+            ->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($principal)))
312
+            ->setMaxResults(1)
313
+            ->execute();
314
+
315
+        $row = $result->fetch();
316
+        $result->closeCursor();
317
+        if ($row === false) {
318
+            return null;
319
+        }
320
+
321
+        $addressBook = [
322
+            'id'  => $row['id'],
323
+            'uri' => $row['uri'],
324
+            'principaluri' => $row['principaluri'],
325
+            '{DAV:}displayname' => $row['displayname'],
326
+            '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
327
+            '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
328
+            '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
329
+        ];
330
+
331
+        $this->addOwnerPrincipal($addressBook);
332
+
333
+        return $addressBook;
334
+    }
335
+
336
+    /**
337
+     * Updates properties for an address book.
338
+     *
339
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
340
+     * To do the actual updates, you must tell this object which properties
341
+     * you're going to process with the handle() method.
342
+     *
343
+     * Calling the handle method is like telling the PropPatch object "I
344
+     * promise I can handle updating this property".
345
+     *
346
+     * Read the PropPatch documentation for more info and examples.
347
+     *
348
+     * @param string $addressBookId
349
+     * @param \Sabre\DAV\PropPatch $propPatch
350
+     * @return void
351
+     */
352
+    function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch) {
353
+        $supportedProperties = [
354
+            '{DAV:}displayname',
355
+            '{' . Plugin::NS_CARDDAV . '}addressbook-description',
356
+        ];
357
+
358
+        /**
359
+         * @suppress SqlInjectionChecker
360
+         */
361
+        $propPatch->handle($supportedProperties, function($mutations) use ($addressBookId) {
362
+
363
+            $updates = [];
364
+            foreach($mutations as $property=>$newValue) {
365
+
366
+                switch($property) {
367
+                    case '{DAV:}displayname' :
368
+                        $updates['displayname'] = $newValue;
369
+                        break;
370
+                    case '{' . Plugin::NS_CARDDAV . '}addressbook-description' :
371
+                        $updates['description'] = $newValue;
372
+                        break;
373
+                }
374
+            }
375
+            $query = $this->db->getQueryBuilder();
376
+            $query->update('addressbooks');
377
+
378
+            foreach($updates as $key=>$value) {
379
+                $query->set($key, $query->createNamedParameter($value));
380
+            }
381
+            $query->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
382
+            ->execute();
383
+
384
+            $this->addChange($addressBookId, "", 2);
385
+
386
+            return true;
387
+
388
+        });
389
+    }
390
+
391
+    /**
392
+     * Creates a new address book
393
+     *
394
+     * @param string $principalUri
395
+     * @param string $url Just the 'basename' of the url.
396
+     * @param array $properties
397
+     * @return int
398
+     * @throws BadRequest
399
+     */
400
+    function createAddressBook($principalUri, $url, array $properties) {
401
+        $values = [
402
+            'displayname' => null,
403
+            'description' => null,
404
+            'principaluri' => $principalUri,
405
+            'uri' => $url,
406
+            'synctoken' => 1
407
+        ];
408
+
409
+        foreach($properties as $property=>$newValue) {
410
+
411
+            switch($property) {
412
+                case '{DAV:}displayname' :
413
+                    $values['displayname'] = $newValue;
414
+                    break;
415
+                case '{' . Plugin::NS_CARDDAV . '}addressbook-description' :
416
+                    $values['description'] = $newValue;
417
+                    break;
418
+                default :
419
+                    throw new BadRequest('Unknown property: ' . $property);
420
+            }
421
+
422
+        }
423
+
424
+        // Fallback to make sure the displayname is set. Some clients may refuse
425
+        // to work with addressbooks not having a displayname.
426
+        if(is_null($values['displayname'])) {
427
+            $values['displayname'] = $url;
428
+        }
429
+
430
+        $query = $this->db->getQueryBuilder();
431
+        $query->insert('addressbooks')
432
+            ->values([
433
+                'uri' => $query->createParameter('uri'),
434
+                'displayname' => $query->createParameter('displayname'),
435
+                'description' => $query->createParameter('description'),
436
+                'principaluri' => $query->createParameter('principaluri'),
437
+                'synctoken' => $query->createParameter('synctoken'),
438
+            ])
439
+            ->setParameters($values)
440
+            ->execute();
441
+
442
+        return $query->getLastInsertId();
443
+    }
444
+
445
+    /**
446
+     * Deletes an entire addressbook and all its contents
447
+     *
448
+     * @param mixed $addressBookId
449
+     * @return void
450
+     */
451
+    function deleteAddressBook($addressBookId) {
452
+        $query = $this->db->getQueryBuilder();
453
+        $query->delete('cards')
454
+            ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
455
+            ->setParameter('addressbookid', $addressBookId)
456
+            ->execute();
457
+
458
+        $query->delete('addressbookchanges')
459
+            ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
460
+            ->setParameter('addressbookid', $addressBookId)
461
+            ->execute();
462
+
463
+        $query->delete('addressbooks')
464
+            ->where($query->expr()->eq('id', $query->createParameter('id')))
465
+            ->setParameter('id', $addressBookId)
466
+            ->execute();
467
+
468
+        $this->sharingBackend->deleteAllShares($addressBookId);
469
+
470
+        $query->delete($this->dbCardsPropertiesTable)
471
+            ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
472
+            ->execute();
473
+
474
+    }
475
+
476
+    /**
477
+     * Returns all cards for a specific addressbook id.
478
+     *
479
+     * This method should return the following properties for each card:
480
+     *   * carddata - raw vcard data
481
+     *   * uri - Some unique url
482
+     *   * lastmodified - A unix timestamp
483
+     *
484
+     * It's recommended to also return the following properties:
485
+     *   * etag - A unique etag. This must change every time the card changes.
486
+     *   * size - The size of the card in bytes.
487
+     *
488
+     * If these last two properties are provided, less time will be spent
489
+     * calculating them. If they are specified, you can also ommit carddata.
490
+     * This may speed up certain requests, especially with large cards.
491
+     *
492
+     * @param mixed $addressBookId
493
+     * @return array
494
+     */
495
+    function getCards($addressBookId) {
496
+        $query = $this->db->getQueryBuilder();
497
+        $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
498
+            ->from('cards')
499
+            ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
500
+
501
+        $cards = [];
502
+
503
+        $result = $query->execute();
504
+        while($row = $result->fetch()) {
505
+            $row['etag'] = '"' . $row['etag'] . '"';
506
+            $row['carddata'] = $this->readBlob($row['carddata']);
507
+            $cards[] = $row;
508
+        }
509
+        $result->closeCursor();
510
+
511
+        return $cards;
512
+    }
513
+
514
+    /**
515
+     * Returns a specific card.
516
+     *
517
+     * The same set of properties must be returned as with getCards. The only
518
+     * exception is that 'carddata' is absolutely required.
519
+     *
520
+     * If the card does not exist, you must return false.
521
+     *
522
+     * @param mixed $addressBookId
523
+     * @param string $cardUri
524
+     * @return array
525
+     */
526
+    function getCard($addressBookId, $cardUri) {
527
+        $query = $this->db->getQueryBuilder();
528
+        $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
529
+            ->from('cards')
530
+            ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
531
+            ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
532
+            ->setMaxResults(1);
533
+
534
+        $result = $query->execute();
535
+        $row = $result->fetch();
536
+        if (!$row) {
537
+            return false;
538
+        }
539
+        $row['etag'] = '"' . $row['etag'] . '"';
540
+        $row['carddata'] = $this->readBlob($row['carddata']);
541
+
542
+        return $row;
543
+    }
544
+
545
+    /**
546
+     * Returns a list of cards.
547
+     *
548
+     * This method should work identical to getCard, but instead return all the
549
+     * cards in the list as an array.
550
+     *
551
+     * If the backend supports this, it may allow for some speed-ups.
552
+     *
553
+     * @param mixed $addressBookId
554
+     * @param string[] $uris
555
+     * @return array
556
+     */
557
+    function getMultipleCards($addressBookId, array $uris) {
558
+        if (empty($uris)) {
559
+            return [];
560
+        }
561
+
562
+        $chunks = array_chunk($uris, 100);
563
+        $cards = [];
564
+
565
+        $query = $this->db->getQueryBuilder();
566
+        $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
567
+            ->from('cards')
568
+            ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
569
+            ->andWhere($query->expr()->in('uri', $query->createParameter('uri')));
570
+
571
+        foreach ($chunks as $uris) {
572
+            $query->setParameter('uri', $uris, IQueryBuilder::PARAM_STR_ARRAY);
573
+            $result = $query->execute();
574
+
575
+            while ($row = $result->fetch()) {
576
+                $row['etag'] = '"' . $row['etag'] . '"';
577
+                $row['carddata'] = $this->readBlob($row['carddata']);
578
+                $cards[] = $row;
579
+            }
580
+            $result->closeCursor();
581
+        }
582
+        return $cards;
583
+    }
584
+
585
+    /**
586
+     * Creates a new card.
587
+     *
588
+     * The addressbook id will be passed as the first argument. This is the
589
+     * same id as it is returned from the getAddressBooksForUser method.
590
+     *
591
+     * The cardUri is a base uri, and doesn't include the full path. The
592
+     * cardData argument is the vcard body, and is passed as a string.
593
+     *
594
+     * It is possible to return an ETag from this method. This ETag is for the
595
+     * newly created resource, and must be enclosed with double quotes (that
596
+     * is, the string itself must contain the double quotes).
597
+     *
598
+     * You should only return the ETag if you store the carddata as-is. If a
599
+     * subsequent GET request on the same card does not have the same body,
600
+     * byte-by-byte and you did return an ETag here, clients tend to get
601
+     * confused.
602
+     *
603
+     * If you don't return an ETag, you can just return null.
604
+     *
605
+     * @param mixed $addressBookId
606
+     * @param string $cardUri
607
+     * @param string $cardData
608
+     * @return string
609
+     */
610
+    function createCard($addressBookId, $cardUri, $cardData) {
611
+        $etag = md5($cardData);
612
+        $uid = $this->getUID($cardData);
613
+
614
+        $q = $this->db->getQueryBuilder();
615
+        $q->select('uid')
616
+            ->from('cards')
617
+            ->where($q->expr()->eq('addressbookid', $q->createNamedParameter($addressBookId)))
618
+            ->andWhere($q->expr()->eq('uid', $q->createNamedParameter($uid)))
619
+            ->setMaxResults(1);
620
+        $result = $q->execute();
621
+        $count = (bool) $result->fetchColumn();
622
+        $result->closeCursor();
623
+        if ($count) {
624
+            throw new \Sabre\DAV\Exception\BadRequest('VCard object with uid already exists in this addressbook collection.');
625
+        }
626
+
627
+        $query = $this->db->getQueryBuilder();
628
+        $query->insert('cards')
629
+            ->values([
630
+                'carddata' => $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB),
631
+                'uri' => $query->createNamedParameter($cardUri),
632
+                'lastmodified' => $query->createNamedParameter(time()),
633
+                'addressbookid' => $query->createNamedParameter($addressBookId),
634
+                'size' => $query->createNamedParameter(strlen($cardData)),
635
+                'etag' => $query->createNamedParameter($etag),
636
+                'uid' => $query->createNamedParameter($uid),
637
+            ])
638
+            ->execute();
639
+
640
+        $this->addChange($addressBookId, $cardUri, 1);
641
+        $this->updateProperties($addressBookId, $cardUri, $cardData);
642
+
643
+        $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::createCard',
644
+            new GenericEvent(null, [
645
+                'addressBookId' => $addressBookId,
646
+                'cardUri' => $cardUri,
647
+                'cardData' => $cardData]));
648
+
649
+        return '"' . $etag . '"';
650
+    }
651
+
652
+    /**
653
+     * Updates a card.
654
+     *
655
+     * The addressbook id will be passed as the first argument. This is the
656
+     * same id as it is returned from the getAddressBooksForUser method.
657
+     *
658
+     * The cardUri is a base uri, and doesn't include the full path. The
659
+     * cardData argument is the vcard body, and is passed as a string.
660
+     *
661
+     * It is possible to return an ETag from this method. This ETag should
662
+     * match that of the updated resource, and must be enclosed with double
663
+     * quotes (that is: the string itself must contain the actual quotes).
664
+     *
665
+     * You should only return the ETag if you store the carddata as-is. If a
666
+     * subsequent GET request on the same card does not have the same body,
667
+     * byte-by-byte and you did return an ETag here, clients tend to get
668
+     * confused.
669
+     *
670
+     * If you don't return an ETag, you can just return null.
671
+     *
672
+     * @param mixed $addressBookId
673
+     * @param string $cardUri
674
+     * @param string $cardData
675
+     * @return string
676
+     */
677
+    function updateCard($addressBookId, $cardUri, $cardData) {
678
+
679
+        $uid = $this->getUID($cardData);
680
+        $etag = md5($cardData);
681
+        $query = $this->db->getQueryBuilder();
682
+        $query->update('cards')
683
+            ->set('carddata', $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB))
684
+            ->set('lastmodified', $query->createNamedParameter(time()))
685
+            ->set('size', $query->createNamedParameter(strlen($cardData)))
686
+            ->set('etag', $query->createNamedParameter($etag))
687
+            ->set('uid', $query->createNamedParameter($uid))
688
+            ->where($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
689
+            ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
690
+            ->execute();
691
+
692
+        $this->addChange($addressBookId, $cardUri, 2);
693
+        $this->updateProperties($addressBookId, $cardUri, $cardData);
694
+
695
+        $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::updateCard',
696
+            new GenericEvent(null, [
697
+                'addressBookId' => $addressBookId,
698
+                'cardUri' => $cardUri,
699
+                'cardData' => $cardData]));
700
+
701
+        return '"' . $etag . '"';
702
+    }
703
+
704
+    /**
705
+     * Deletes a card
706
+     *
707
+     * @param mixed $addressBookId
708
+     * @param string $cardUri
709
+     * @return bool
710
+     */
711
+    function deleteCard($addressBookId, $cardUri) {
712
+        try {
713
+            $cardId = $this->getCardId($addressBookId, $cardUri);
714
+        } catch (\InvalidArgumentException $e) {
715
+            $cardId = null;
716
+        }
717
+        $query = $this->db->getQueryBuilder();
718
+        $ret = $query->delete('cards')
719
+            ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
720
+            ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
721
+            ->execute();
722
+
723
+        $this->addChange($addressBookId, $cardUri, 3);
724
+
725
+        $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::deleteCard',
726
+            new GenericEvent(null, [
727
+                'addressBookId' => $addressBookId,
728
+                'cardUri' => $cardUri]));
729
+
730
+        if ($ret === 1) {
731
+            if ($cardId !== null) {
732
+                $this->purgeProperties($addressBookId, $cardId);
733
+            }
734
+            return true;
735
+        }
736
+
737
+        return false;
738
+    }
739
+
740
+    /**
741
+     * The getChanges method returns all the changes that have happened, since
742
+     * the specified syncToken in the specified address book.
743
+     *
744
+     * This function should return an array, such as the following:
745
+     *
746
+     * [
747
+     *   'syncToken' => 'The current synctoken',
748
+     *   'added'   => [
749
+     *      'new.txt',
750
+     *   ],
751
+     *   'modified'   => [
752
+     *      'modified.txt',
753
+     *   ],
754
+     *   'deleted' => [
755
+     *      'foo.php.bak',
756
+     *      'old.txt'
757
+     *   ]
758
+     * ];
759
+     *
760
+     * The returned syncToken property should reflect the *current* syncToken
761
+     * of the calendar, as reported in the {http://sabredav.org/ns}sync-token
762
+     * property. This is needed here too, to ensure the operation is atomic.
763
+     *
764
+     * If the $syncToken argument is specified as null, this is an initial
765
+     * sync, and all members should be reported.
766
+     *
767
+     * The modified property is an array of nodenames that have changed since
768
+     * the last token.
769
+     *
770
+     * The deleted property is an array with nodenames, that have been deleted
771
+     * from collection.
772
+     *
773
+     * The $syncLevel argument is basically the 'depth' of the report. If it's
774
+     * 1, you only have to report changes that happened only directly in
775
+     * immediate descendants. If it's 2, it should also include changes from
776
+     * the nodes below the child collections. (grandchildren)
777
+     *
778
+     * The $limit argument allows a client to specify how many results should
779
+     * be returned at most. If the limit is not specified, it should be treated
780
+     * as infinite.
781
+     *
782
+     * If the limit (infinite or not) is higher than you're willing to return,
783
+     * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
784
+     *
785
+     * If the syncToken is expired (due to data cleanup) or unknown, you must
786
+     * return null.
787
+     *
788
+     * The limit is 'suggestive'. You are free to ignore it.
789
+     *
790
+     * @param string $addressBookId
791
+     * @param string $syncToken
792
+     * @param int $syncLevel
793
+     * @param int $limit
794
+     * @return array
795
+     */
796
+    function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null) {
797
+        // Current synctoken
798
+        $stmt = $this->db->prepare('SELECT `synctoken` FROM `*PREFIX*addressbooks` WHERE `id` = ?');
799
+        $stmt->execute([ $addressBookId ]);
800
+        $currentToken = $stmt->fetchColumn(0);
801
+
802
+        if (is_null($currentToken)) return null;
803
+
804
+        $result = [
805
+            'syncToken' => $currentToken,
806
+            'added'     => [],
807
+            'modified'  => [],
808
+            'deleted'   => [],
809
+        ];
810
+
811
+        if ($syncToken) {
812
+
813
+            $query = "SELECT `uri`, `operation` FROM `*PREFIX*addressbookchanges` WHERE `synctoken` >= ? AND `synctoken` < ? AND `addressbookid` = ? ORDER BY `synctoken`";
814
+            if ($limit>0) {
815
+                $query .= " `LIMIT` " . (int)$limit;
816
+            }
817
+
818
+            // Fetching all changes
819
+            $stmt = $this->db->prepare($query);
820
+            $stmt->execute([$syncToken, $currentToken, $addressBookId]);
821
+
822
+            $changes = [];
823
+
824
+            // This loop ensures that any duplicates are overwritten, only the
825
+            // last change on a node is relevant.
826
+            while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
827
+
828
+                $changes[$row['uri']] = $row['operation'];
829
+
830
+            }
831
+
832
+            foreach($changes as $uri => $operation) {
833
+
834
+                switch($operation) {
835
+                    case 1:
836
+                        $result['added'][] = $uri;
837
+                        break;
838
+                    case 2:
839
+                        $result['modified'][] = $uri;
840
+                        break;
841
+                    case 3:
842
+                        $result['deleted'][] = $uri;
843
+                        break;
844
+                }
845
+
846
+            }
847
+        } else {
848
+            // No synctoken supplied, this is the initial sync.
849
+            $query = "SELECT `uri` FROM `*PREFIX*cards` WHERE `addressbookid` = ?";
850
+            $stmt = $this->db->prepare($query);
851
+            $stmt->execute([$addressBookId]);
852
+
853
+            $result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN);
854
+        }
855
+        return $result;
856
+    }
857
+
858
+    /**
859
+     * Adds a change record to the addressbookchanges table.
860
+     *
861
+     * @param mixed $addressBookId
862
+     * @param string $objectUri
863
+     * @param int $operation 1 = add, 2 = modify, 3 = delete
864
+     * @return void
865
+     */
866
+    protected function addChange($addressBookId, $objectUri, $operation) {
867
+        $sql = 'INSERT INTO `*PREFIX*addressbookchanges`(`uri`, `synctoken`, `addressbookid`, `operation`) SELECT ?, `synctoken`, ?, ? FROM `*PREFIX*addressbooks` WHERE `id` = ?';
868
+        $stmt = $this->db->prepare($sql);
869
+        $stmt->execute([
870
+            $objectUri,
871
+            $addressBookId,
872
+            $operation,
873
+            $addressBookId
874
+        ]);
875
+        $stmt = $this->db->prepare('UPDATE `*PREFIX*addressbooks` SET `synctoken` = `synctoken` + 1 WHERE `id` = ?');
876
+        $stmt->execute([
877
+            $addressBookId
878
+        ]);
879
+    }
880
+
881
+    private function readBlob($cardData) {
882
+        if (is_resource($cardData)) {
883
+            return stream_get_contents($cardData);
884
+        }
885
+
886
+        return $cardData;
887
+    }
888
+
889
+    /**
890
+     * @param IShareable $shareable
891
+     * @param string[] $add
892
+     * @param string[] $remove
893
+     */
894
+    public function updateShares(IShareable $shareable, $add, $remove) {
895
+        $this->sharingBackend->updateShares($shareable, $add, $remove);
896
+    }
897
+
898
+    /**
899
+     * search contact
900
+     *
901
+     * @param int $addressBookId
902
+     * @param string $pattern which should match within the $searchProperties
903
+     * @param array $searchProperties defines the properties within the query pattern should match
904
+     * @return array an array of contacts which are arrays of key-value-pairs
905
+     */
906
+    public function search($addressBookId, $pattern, $searchProperties) {
907
+        $query = $this->db->getQueryBuilder();
908
+        $query2 = $this->db->getQueryBuilder();
909
+
910
+        $query2->selectDistinct('cp.cardid')->from($this->dbCardsPropertiesTable, 'cp');
911
+        $query2->andWhere($query2->expr()->eq('cp.addressbookid', $query->createNamedParameter($addressBookId)));
912
+        $or = $query2->expr()->orX();
913
+        foreach ($searchProperties as $property) {
914
+            $or->add($query2->expr()->eq('cp.name', $query->createNamedParameter($property)));
915
+        }
916
+        $query2->andWhere($or);
917
+
918
+        // No need for like when the pattern is empty
919
+        if ('' !== $pattern) {
920
+            $query2->andWhere($query2->expr()->ilike('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')));
921
+        }
922
+
923
+        $query->select('c.carddata', 'c.uri')->from($this->dbCardsTable, 'c')
924
+            ->where($query->expr()->in('c.id', $query->createFunction($query2->getSQL())));
925
+
926
+        $result = $query->execute();
927
+        $cards = $result->fetchAll();
928
+
929
+        $result->closeCursor();
930
+
931
+        return array_map(function($array) {
932
+            $array['carddata'] = $this->readBlob($array['carddata']);
933
+            return $array;
934
+        }, $cards);
935
+    }
936
+
937
+    /**
938
+     * @param int $bookId
939
+     * @param string $name
940
+     * @return array
941
+     */
942
+    public function collectCardProperties($bookId, $name) {
943
+        $query = $this->db->getQueryBuilder();
944
+        $result = $query->selectDistinct('value')
945
+            ->from($this->dbCardsPropertiesTable)
946
+            ->where($query->expr()->eq('name', $query->createNamedParameter($name)))
947
+            ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($bookId)))
948
+            ->execute();
949
+
950
+        $all = $result->fetchAll(PDO::FETCH_COLUMN);
951
+        $result->closeCursor();
952
+
953
+        return $all;
954
+    }
955
+
956
+    /**
957
+     * get URI from a given contact
958
+     *
959
+     * @param int $id
960
+     * @return string
961
+     */
962
+    public function getCardUri($id) {
963
+        $query = $this->db->getQueryBuilder();
964
+        $query->select('uri')->from($this->dbCardsTable)
965
+                ->where($query->expr()->eq('id', $query->createParameter('id')))
966
+                ->setParameter('id', $id);
967
+
968
+        $result = $query->execute();
969
+        $uri = $result->fetch();
970
+        $result->closeCursor();
971
+
972
+        if (!isset($uri['uri'])) {
973
+            throw new \InvalidArgumentException('Card does not exists: ' . $id);
974
+        }
975
+
976
+        return $uri['uri'];
977
+    }
978
+
979
+    /**
980
+     * return contact with the given URI
981
+     *
982
+     * @param int $addressBookId
983
+     * @param string $uri
984
+     * @returns array
985
+     */
986
+    public function getContact($addressBookId, $uri) {
987
+        $result = [];
988
+        $query = $this->db->getQueryBuilder();
989
+        $query->select('*')->from($this->dbCardsTable)
990
+                ->where($query->expr()->eq('uri', $query->createNamedParameter($uri)))
991
+                ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
992
+        $queryResult = $query->execute();
993
+        $contact = $queryResult->fetch();
994
+        $queryResult->closeCursor();
995
+
996
+        if (is_array($contact)) {
997
+            $result = $contact;
998
+        }
999
+
1000
+        return $result;
1001
+    }
1002
+
1003
+    /**
1004
+     * Returns the list of people whom this address book is shared with.
1005
+     *
1006
+     * Every element in this array should have the following properties:
1007
+     *   * href - Often a mailto: address
1008
+     *   * commonName - Optional, for example a first + last name
1009
+     *   * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
1010
+     *   * readOnly - boolean
1011
+     *   * summary - Optional, a description for the share
1012
+     *
1013
+     * @return array
1014
+     */
1015
+    public function getShares($addressBookId) {
1016
+        return $this->sharingBackend->getShares($addressBookId);
1017
+    }
1018
+
1019
+    /**
1020
+     * update properties table
1021
+     *
1022
+     * @param int $addressBookId
1023
+     * @param string $cardUri
1024
+     * @param string $vCardSerialized
1025
+     */
1026
+    protected function updateProperties($addressBookId, $cardUri, $vCardSerialized) {
1027
+        $cardId = $this->getCardId($addressBookId, $cardUri);
1028
+        $vCard = $this->readCard($vCardSerialized);
1029
+
1030
+        $this->purgeProperties($addressBookId, $cardId);
1031
+
1032
+        $query = $this->db->getQueryBuilder();
1033
+        $query->insert($this->dbCardsPropertiesTable)
1034
+            ->values(
1035
+                [
1036
+                    'addressbookid' => $query->createNamedParameter($addressBookId),
1037
+                    'cardid' => $query->createNamedParameter($cardId),
1038
+                    'name' => $query->createParameter('name'),
1039
+                    'value' => $query->createParameter('value'),
1040
+                    'preferred' => $query->createParameter('preferred')
1041
+                ]
1042
+            );
1043
+
1044
+        foreach ($vCard->children() as $property) {
1045
+            if(!in_array($property->name, self::$indexProperties)) {
1046
+                continue;
1047
+            }
1048
+            $preferred = 0;
1049
+            foreach($property->parameters as $parameter) {
1050
+                if ($parameter->name === 'TYPE' && strtoupper($parameter->getValue()) === 'PREF') {
1051
+                    $preferred = 1;
1052
+                    break;
1053
+                }
1054
+            }
1055
+            $query->setParameter('name', $property->name);
1056
+            $query->setParameter('value', substr($property->getValue(), 0, 254));
1057
+            $query->setParameter('preferred', $preferred);
1058
+            $query->execute();
1059
+        }
1060
+    }
1061
+
1062
+    /**
1063
+     * read vCard data into a vCard object
1064
+     *
1065
+     * @param string $cardData
1066
+     * @return VCard
1067
+     */
1068
+    protected function readCard($cardData) {
1069
+        return  Reader::read($cardData);
1070
+    }
1071
+
1072
+    /**
1073
+     * delete all properties from a given card
1074
+     *
1075
+     * @param int $addressBookId
1076
+     * @param int $cardId
1077
+     */
1078
+    protected function purgeProperties($addressBookId, $cardId) {
1079
+        $query = $this->db->getQueryBuilder();
1080
+        $query->delete($this->dbCardsPropertiesTable)
1081
+            ->where($query->expr()->eq('cardid', $query->createNamedParameter($cardId)))
1082
+            ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
1083
+        $query->execute();
1084
+    }
1085
+
1086
+    /**
1087
+     * get ID from a given contact
1088
+     *
1089
+     * @param int $addressBookId
1090
+     * @param string $uri
1091
+     * @return int
1092
+     */
1093
+    protected function getCardId($addressBookId, $uri) {
1094
+        $query = $this->db->getQueryBuilder();
1095
+        $query->select('id')->from($this->dbCardsTable)
1096
+            ->where($query->expr()->eq('uri', $query->createNamedParameter($uri)))
1097
+            ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
1098
+
1099
+        $result = $query->execute();
1100
+        $cardIds = $result->fetch();
1101
+        $result->closeCursor();
1102
+
1103
+        if (!isset($cardIds['id'])) {
1104
+            throw new \InvalidArgumentException('Card does not exists: ' . $uri);
1105
+        }
1106
+
1107
+        return (int)$cardIds['id'];
1108
+    }
1109
+
1110
+    /**
1111
+     * For shared address books the sharee is set in the ACL of the address book
1112
+     * @param $addressBookId
1113
+     * @param $acl
1114
+     * @return array
1115
+     */
1116
+    public function applyShareAcl($addressBookId, $acl) {
1117
+        return $this->sharingBackend->applyShareAcl($addressBookId, $acl);
1118
+    }
1119
+
1120
+    private function convertPrincipal($principalUri, $toV2) {
1121
+        if ($this->principalBackend->getPrincipalPrefix() === 'principals') {
1122
+            list(, $name) = \Sabre\Uri\split($principalUri);
1123
+            if ($toV2 === true) {
1124
+                return "principals/users/$name";
1125
+            }
1126
+            return "principals/$name";
1127
+        }
1128
+        return $principalUri;
1129
+    }
1130
+
1131
+    private function addOwnerPrincipal(&$addressbookInfo) {
1132
+        $ownerPrincipalKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal';
1133
+        $displaynameKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}owner-displayname';
1134
+        if (isset($addressbookInfo[$ownerPrincipalKey])) {
1135
+            $uri = $addressbookInfo[$ownerPrincipalKey];
1136
+        } else {
1137
+            $uri = $addressbookInfo['principaluri'];
1138
+        }
1139
+
1140
+        $principalInformation = $this->principalBackend->getPrincipalByPath($uri);
1141
+        if (isset($principalInformation['{DAV:}displayname'])) {
1142
+            $addressbookInfo[$displaynameKey] = $principalInformation['{DAV:}displayname'];
1143
+        }
1144
+    }
1145
+
1146
+    /**
1147
+     * Extract UID from vcard
1148
+     *
1149
+     * @param string $cardData the vcard raw data
1150
+     * @return string the uid
1151
+     * @throws BadRequest if no UID is available
1152
+     */
1153
+    private function getUID($cardData) {
1154
+        if ($cardData != '') {
1155
+            $vCard = Reader::read($cardData);
1156
+            if ($vCard->UID) {
1157
+                $uid = $vCard->UID->getValue();
1158
+                return $uid;
1159
+            }
1160
+            // should already be handled, but just in case
1161
+            throw new BadRequest('vCards on CardDAV servers MUST have a UID property');
1162
+        }
1163
+        // should already be handled, but just in case
1164
+        throw new BadRequest('vCard can not be empty');
1165
+    }
1166 1166
 }
Please login to merge, or discard this patch.
apps/dav/lib/CardDAV/UserAddressBooks.php 2 patches
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -25,52 +25,52 @@
 block discarded – undo
25 25
 
26 26
 class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome {
27 27
 
28
-	/** @var IL10N */
29
-	protected $l10n;
28
+    /** @var IL10N */
29
+    protected $l10n;
30 30
 
31
-	/**
32
-	 * Returns a list of addressbooks
33
-	 *
34
-	 * @return array
35
-	 */
36
-	function getChildren() {
37
-		if ($this->l10n === null) {
38
-			$this->l10n = \OC::$server->getL10N('dav');
39
-		}
31
+    /**
32
+     * Returns a list of addressbooks
33
+     *
34
+     * @return array
35
+     */
36
+    function getChildren() {
37
+        if ($this->l10n === null) {
38
+            $this->l10n = \OC::$server->getL10N('dav');
39
+        }
40 40
 
41
-		$addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri);
42
-		$objects = [];
43
-		foreach($addressBooks as $addressBook) {
44
-			$objects[] = new AddressBook($this->carddavBackend, $addressBook, $this->l10n);
45
-		}
46
-		return $objects;
41
+        $addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri);
42
+        $objects = [];
43
+        foreach($addressBooks as $addressBook) {
44
+            $objects[] = new AddressBook($this->carddavBackend, $addressBook, $this->l10n);
45
+        }
46
+        return $objects;
47 47
 
48
-	}
48
+    }
49 49
 
50
-	/**
51
-	 * Returns a list of ACE's for this node.
52
-	 *
53
-	 * Each ACE has the following properties:
54
-	 *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
55
-	 *     currently the only supported privileges
56
-	 *   * 'principal', a url to the principal who owns the node
57
-	 *   * 'protected' (optional), indicating that this ACE is not allowed to
58
-	 *      be updated.
59
-	 *
60
-	 * @return array
61
-	 */
62
-	function getACL() {
50
+    /**
51
+     * Returns a list of ACE's for this node.
52
+     *
53
+     * Each ACE has the following properties:
54
+     *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
55
+     *     currently the only supported privileges
56
+     *   * 'principal', a url to the principal who owns the node
57
+     *   * 'protected' (optional), indicating that this ACE is not allowed to
58
+     *      be updated.
59
+     *
60
+     * @return array
61
+     */
62
+    function getACL() {
63 63
 
64
-		$acl = parent::getACL();
65
-		if ($this->principalUri === 'principals/system/system') {
66
-			$acl[] = [
67
-					'privilege' => '{DAV:}read',
68
-					'principal' => '{DAV:}authenticated',
69
-					'protected' => true,
70
-			];
71
-		}
64
+        $acl = parent::getACL();
65
+        if ($this->principalUri === 'principals/system/system') {
66
+            $acl[] = [
67
+                    'privilege' => '{DAV:}read',
68
+                    'principal' => '{DAV:}authenticated',
69
+                    'protected' => true,
70
+            ];
71
+        }
72 72
 
73
-		return $acl;
74
-	}
73
+        return $acl;
74
+    }
75 75
 
76 76
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -40,7 +40,7 @@
 block discarded – undo
40 40
 
41 41
 		$addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri);
42 42
 		$objects = [];
43
-		foreach($addressBooks as $addressBook) {
43
+		foreach ($addressBooks as $addressBook) {
44 44
 			$objects[] = new AddressBook($this->carddavBackend, $addressBook, $this->l10n);
45 45
 		}
46 46
 		return $objects;
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagNode.php 2 patches
Indentation   +132 added lines, -132 removed lines patch added patch discarded remove patch
@@ -39,136 +39,136 @@
 block discarded – undo
39 39
  */
40 40
 class SystemTagNode implements \Sabre\DAV\INode {
41 41
 
42
-	/**
43
-	 * @var ISystemTag
44
-	 */
45
-	protected $tag;
46
-
47
-	/**
48
-	 * @var ISystemTagManager
49
-	 */
50
-	protected $tagManager;
51
-
52
-	/**
53
-	 * User
54
-	 *
55
-	 * @var IUser
56
-	 */
57
-	protected $user;
58
-
59
-	/**
60
-	 * Whether to allow permissions for admins
61
-	 *
62
-	 * @var bool
63
-	 */
64
-	protected $isAdmin;
65
-
66
-	/**
67
-	 * Sets up the node, expects a full path name
68
-	 *
69
-	 * @param ISystemTag $tag system tag
70
-	 * @param IUser $user user
71
-	 * @param bool $isAdmin whether to allow operations for admins
72
-	 * @param ISystemTagManager $tagManager tag manager
73
-	 */
74
-	public function __construct(ISystemTag $tag, IUser $user, $isAdmin, ISystemTagManager $tagManager) {
75
-		$this->tag = $tag;
76
-		$this->user = $user;
77
-		$this->isAdmin = $isAdmin;
78
-		$this->tagManager = $tagManager;
79
-	}
80
-
81
-	/**
82
-	 *  Returns the id of the tag
83
-	 *
84
-	 * @return string
85
-	 */
86
-	public function getName() {
87
-		return $this->tag->getId();
88
-	}
89
-
90
-	/**
91
-	 * Returns the system tag represented by this node
92
-	 *
93
-	 * @return ISystemTag system tag
94
-	 */
95
-	public function getSystemTag() {
96
-		return $this->tag;
97
-	}
98
-
99
-	/**
100
-	 * Renames the node
101
-	 *
102
-	 * @param string $name The new name
103
-	 *
104
-	 * @throws MethodNotAllowed not allowed to rename node
105
-	 */
106
-	public function setName($name) {
107
-		throw new MethodNotAllowed();
108
-	}
109
-
110
-	/**
111
-	 * Update tag
112
-	 *
113
-	 * @param string $name new tag name
114
-	 * @param bool $userVisible user visible
115
-	 * @param bool $userAssignable user assignable
116
-	 * @throws NotFound whenever the given tag id does not exist
117
-	 * @throws Forbidden whenever there is no permission to update said tag
118
-	 * @throws Conflict whenever a tag already exists with the given attributes
119
-	 */
120
-	public function update($name, $userVisible, $userAssignable) {
121
-		try {
122
-			if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
123
-				throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
124
-			}
125
-			if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) {
126
-				throw new Forbidden('No permission to update tag ' . $this->tag->getId());
127
-			}
128
-
129
-			// only admin is able to change permissions, regular users can only rename
130
-			if (!$this->isAdmin) {
131
-				// only renaming is allowed for regular users
132
-				if ($userVisible !== $this->tag->isUserVisible()
133
-					|| $userAssignable !== $this->tag->isUserAssignable()
134
-				) {
135
-					throw new Forbidden('No permission to update permissions for tag ' . $this->tag->getId());
136
-				}
137
-			}
138
-
139
-			$this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable);
140
-		} catch (TagNotFoundException $e) {
141
-			throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
142
-		} catch (TagAlreadyExistsException $e) {
143
-			throw new Conflict(
144
-				'Tag with the properties "' . $name . '", ' .
145
-				$userVisible . ', ' . $userAssignable . ' already exists'
146
-			);
147
-		}
148
-	}
149
-
150
-	/**
151
-	 * Returns null, not supported
152
-	 *
153
-	 */
154
-	public function getLastModified() {
155
-		return null;
156
-	}
157
-
158
-	public function delete() {
159
-		try {
160
-			if (!$this->isAdmin) {
161
-				throw new Forbidden('No permission to delete tag ' . $this->tag->getId());
162
-			}
163
-
164
-			if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
165
-				throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found');
166
-			}
167
-
168
-			$this->tagManager->deleteTags($this->tag->getId());
169
-		} catch (TagNotFoundException $e) {
170
-			// can happen if concurrent deletion occurred
171
-			throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
172
-		}
173
-	}
42
+    /**
43
+     * @var ISystemTag
44
+     */
45
+    protected $tag;
46
+
47
+    /**
48
+     * @var ISystemTagManager
49
+     */
50
+    protected $tagManager;
51
+
52
+    /**
53
+     * User
54
+     *
55
+     * @var IUser
56
+     */
57
+    protected $user;
58
+
59
+    /**
60
+     * Whether to allow permissions for admins
61
+     *
62
+     * @var bool
63
+     */
64
+    protected $isAdmin;
65
+
66
+    /**
67
+     * Sets up the node, expects a full path name
68
+     *
69
+     * @param ISystemTag $tag system tag
70
+     * @param IUser $user user
71
+     * @param bool $isAdmin whether to allow operations for admins
72
+     * @param ISystemTagManager $tagManager tag manager
73
+     */
74
+    public function __construct(ISystemTag $tag, IUser $user, $isAdmin, ISystemTagManager $tagManager) {
75
+        $this->tag = $tag;
76
+        $this->user = $user;
77
+        $this->isAdmin = $isAdmin;
78
+        $this->tagManager = $tagManager;
79
+    }
80
+
81
+    /**
82
+     *  Returns the id of the tag
83
+     *
84
+     * @return string
85
+     */
86
+    public function getName() {
87
+        return $this->tag->getId();
88
+    }
89
+
90
+    /**
91
+     * Returns the system tag represented by this node
92
+     *
93
+     * @return ISystemTag system tag
94
+     */
95
+    public function getSystemTag() {
96
+        return $this->tag;
97
+    }
98
+
99
+    /**
100
+     * Renames the node
101
+     *
102
+     * @param string $name The new name
103
+     *
104
+     * @throws MethodNotAllowed not allowed to rename node
105
+     */
106
+    public function setName($name) {
107
+        throw new MethodNotAllowed();
108
+    }
109
+
110
+    /**
111
+     * Update tag
112
+     *
113
+     * @param string $name new tag name
114
+     * @param bool $userVisible user visible
115
+     * @param bool $userAssignable user assignable
116
+     * @throws NotFound whenever the given tag id does not exist
117
+     * @throws Forbidden whenever there is no permission to update said tag
118
+     * @throws Conflict whenever a tag already exists with the given attributes
119
+     */
120
+    public function update($name, $userVisible, $userAssignable) {
121
+        try {
122
+            if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
123
+                throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
124
+            }
125
+            if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) {
126
+                throw new Forbidden('No permission to update tag ' . $this->tag->getId());
127
+            }
128
+
129
+            // only admin is able to change permissions, regular users can only rename
130
+            if (!$this->isAdmin) {
131
+                // only renaming is allowed for regular users
132
+                if ($userVisible !== $this->tag->isUserVisible()
133
+                    || $userAssignable !== $this->tag->isUserAssignable()
134
+                ) {
135
+                    throw new Forbidden('No permission to update permissions for tag ' . $this->tag->getId());
136
+                }
137
+            }
138
+
139
+            $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable);
140
+        } catch (TagNotFoundException $e) {
141
+            throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
142
+        } catch (TagAlreadyExistsException $e) {
143
+            throw new Conflict(
144
+                'Tag with the properties "' . $name . '", ' .
145
+                $userVisible . ', ' . $userAssignable . ' already exists'
146
+            );
147
+        }
148
+    }
149
+
150
+    /**
151
+     * Returns null, not supported
152
+     *
153
+     */
154
+    public function getLastModified() {
155
+        return null;
156
+    }
157
+
158
+    public function delete() {
159
+        try {
160
+            if (!$this->isAdmin) {
161
+                throw new Forbidden('No permission to delete tag ' . $this->tag->getId());
162
+            }
163
+
164
+            if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
165
+                throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found');
166
+            }
167
+
168
+            $this->tagManager->deleteTags($this->tag->getId());
169
+        } catch (TagNotFoundException $e) {
170
+            // can happen if concurrent deletion occurred
171
+            throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
172
+        }
173
+    }
174 174
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -120,10 +120,10 @@  discard block
 block discarded – undo
120 120
 	public function update($name, $userVisible, $userAssignable) {
121 121
 		try {
122 122
 			if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
123
-				throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
123
+				throw new NotFound('Tag with id '.$this->tag->getId().' does not exist');
124 124
 			}
125 125
 			if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) {
126
-				throw new Forbidden('No permission to update tag ' . $this->tag->getId());
126
+				throw new Forbidden('No permission to update tag '.$this->tag->getId());
127 127
 			}
128 128
 
129 129
 			// only admin is able to change permissions, regular users can only rename
@@ -132,17 +132,17 @@  discard block
 block discarded – undo
132 132
 				if ($userVisible !== $this->tag->isUserVisible()
133 133
 					|| $userAssignable !== $this->tag->isUserAssignable()
134 134
 				) {
135
-					throw new Forbidden('No permission to update permissions for tag ' . $this->tag->getId());
135
+					throw new Forbidden('No permission to update permissions for tag '.$this->tag->getId());
136 136
 				}
137 137
 			}
138 138
 
139 139
 			$this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable);
140 140
 		} catch (TagNotFoundException $e) {
141
-			throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
141
+			throw new NotFound('Tag with id '.$this->tag->getId().' does not exist');
142 142
 		} catch (TagAlreadyExistsException $e) {
143 143
 			throw new Conflict(
144
-				'Tag with the properties "' . $name . '", ' .
145
-				$userVisible . ', ' . $userAssignable . ' already exists'
144
+				'Tag with the properties "'.$name.'", '.
145
+				$userVisible.', '.$userAssignable.' already exists'
146 146
 			);
147 147
 		}
148 148
 	}
@@ -158,17 +158,17 @@  discard block
 block discarded – undo
158 158
 	public function delete() {
159 159
 		try {
160 160
 			if (!$this->isAdmin) {
161
-				throw new Forbidden('No permission to delete tag ' . $this->tag->getId());
161
+				throw new Forbidden('No permission to delete tag '.$this->tag->getId());
162 162
 			}
163 163
 
164 164
 			if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
165
-				throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found');
165
+				throw new NotFound('Tag with id '.$this->tag->getId().' not found');
166 166
 			}
167 167
 
168 168
 			$this->tagManager->deleteTags($this->tag->getId());
169 169
 		} catch (TagNotFoundException $e) {
170 170
 			// can happen if concurrent deletion occurred
171
-			throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
171
+			throw new NotFound('Tag with id '.$this->tag->getId().' not found', 0, $e);
172 172
 		}
173 173
 	}
174 174
 }
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagsByIdCollection.php 2 patches
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -37,144 +37,144 @@
 block discarded – undo
37 37
 
38 38
 class SystemTagsByIdCollection implements ICollection {
39 39
 
40
-	/**
41
-	 * @var ISystemTagManager
42
-	 */
43
-	private $tagManager;
44
-
45
-	/**
46
-	 * @var IGroupManager
47
-	 */
48
-	private $groupManager;
49
-
50
-	/**
51
-	 * @var IUserSession
52
-	 */
53
-	private $userSession;
54
-
55
-	/**
56
-	 * SystemTagsByIdCollection constructor.
57
-	 *
58
-	 * @param ISystemTagManager $tagManager
59
-	 * @param IUserSession $userSession
60
-	 * @param IGroupManager $groupManager
61
-	 */
62
-	public function __construct(
63
-		ISystemTagManager $tagManager,
64
-		IUserSession $userSession,
65
-		IGroupManager $groupManager
66
-	) {
67
-		$this->tagManager = $tagManager;
68
-		$this->userSession = $userSession;
69
-		$this->groupManager = $groupManager;
70
-	}
71
-
72
-	/**
73
-	 * Returns whether the currently logged in user is an administrator
74
-	 *
75
-	 * @return bool true if the user is an admin
76
-	 */
77
-	private function isAdmin() {
78
-		$user = $this->userSession->getUser();
79
-		if ($user !== null) {
80
-			return $this->groupManager->isAdmin($user->getUID());
81
-		}
82
-		return false;
83
-	}
84
-
85
-	/**
86
-	 * @param string $name
87
-	 * @param resource|string $data Initial payload
88
-	 * @throws Forbidden
89
-	 */
90
-	function createFile($name, $data = null) {
91
-		throw new Forbidden('Cannot create tags by id');
92
-	}
93
-
94
-	/**
95
-	 * @param string $name
96
-	 */
97
-	function createDirectory($name) {
98
-		throw new Forbidden('Permission denied to create collections');
99
-	}
100
-
101
-	/**
102
-	 * @param string $name
103
-	 */
104
-	function getChild($name) {
105
-		try {
106
-			$tag = $this->tagManager->getTagsByIds([$name]);
107
-			$tag = current($tag);
108
-			if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
109
-				throw new NotFound('Tag with id ' . $name . ' not found');
110
-			}
111
-			return $this->makeNode($tag);
112
-		} catch (\InvalidArgumentException $e) {
113
-			throw new BadRequest('Invalid tag id', 0, $e);
114
-		} catch (TagNotFoundException $e) {
115
-			throw new NotFound('Tag with id ' . $name . ' not found', 0, $e);
116
-		}
117
-	}
118
-
119
-	function getChildren() {
120
-		$visibilityFilter = true;
121
-		if ($this->isAdmin()) {
122
-			$visibilityFilter = null;
123
-		}
124
-
125
-		$tags = $this->tagManager->getAllTags($visibilityFilter);
126
-		return array_map(function($tag) {
127
-			return $this->makeNode($tag);
128
-		}, $tags);
129
-	}
130
-
131
-	/**
132
-	 * @param string $name
133
-	 */
134
-	function childExists($name) {
135
-		try {
136
-			$tag = $this->tagManager->getTagsByIds([$name]);
137
-			$tag = current($tag);
138
-			if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
139
-				return false;
140
-			}
141
-			return true;
142
-		} catch (\InvalidArgumentException $e) {
143
-			throw new BadRequest('Invalid tag id', 0, $e);
144
-		} catch (TagNotFoundException $e) {
145
-			return false;
146
-		}
147
-	}
148
-
149
-	function delete() {
150
-		throw new Forbidden('Permission denied to delete this collection');
151
-	}
152
-
153
-	function getName() {
154
-		return 'systemtags';
155
-	}
156
-
157
-	function setName($name) {
158
-		throw new Forbidden('Permission denied to rename this collection');
159
-	}
160
-
161
-	/**
162
-	 * Returns the last modification time, as a unix timestamp
163
-	 *
164
-	 * @return int
165
-	 */
166
-	function getLastModified() {
167
-		return null;
168
-	}
169
-
170
-	/**
171
-	 * Create a sabre node for the given system tag
172
-	 *
173
-	 * @param ISystemTag $tag
174
-	 *
175
-	 * @return SystemTagNode
176
-	 */
177
-	private function makeNode(ISystemTag $tag) {
178
-		return new SystemTagNode($tag, $this->userSession->getUser(), $this->isAdmin(), $this->tagManager);
179
-	}
40
+    /**
41
+     * @var ISystemTagManager
42
+     */
43
+    private $tagManager;
44
+
45
+    /**
46
+     * @var IGroupManager
47
+     */
48
+    private $groupManager;
49
+
50
+    /**
51
+     * @var IUserSession
52
+     */
53
+    private $userSession;
54
+
55
+    /**
56
+     * SystemTagsByIdCollection constructor.
57
+     *
58
+     * @param ISystemTagManager $tagManager
59
+     * @param IUserSession $userSession
60
+     * @param IGroupManager $groupManager
61
+     */
62
+    public function __construct(
63
+        ISystemTagManager $tagManager,
64
+        IUserSession $userSession,
65
+        IGroupManager $groupManager
66
+    ) {
67
+        $this->tagManager = $tagManager;
68
+        $this->userSession = $userSession;
69
+        $this->groupManager = $groupManager;
70
+    }
71
+
72
+    /**
73
+     * Returns whether the currently logged in user is an administrator
74
+     *
75
+     * @return bool true if the user is an admin
76
+     */
77
+    private function isAdmin() {
78
+        $user = $this->userSession->getUser();
79
+        if ($user !== null) {
80
+            return $this->groupManager->isAdmin($user->getUID());
81
+        }
82
+        return false;
83
+    }
84
+
85
+    /**
86
+     * @param string $name
87
+     * @param resource|string $data Initial payload
88
+     * @throws Forbidden
89
+     */
90
+    function createFile($name, $data = null) {
91
+        throw new Forbidden('Cannot create tags by id');
92
+    }
93
+
94
+    /**
95
+     * @param string $name
96
+     */
97
+    function createDirectory($name) {
98
+        throw new Forbidden('Permission denied to create collections');
99
+    }
100
+
101
+    /**
102
+     * @param string $name
103
+     */
104
+    function getChild($name) {
105
+        try {
106
+            $tag = $this->tagManager->getTagsByIds([$name]);
107
+            $tag = current($tag);
108
+            if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
109
+                throw new NotFound('Tag with id ' . $name . ' not found');
110
+            }
111
+            return $this->makeNode($tag);
112
+        } catch (\InvalidArgumentException $e) {
113
+            throw new BadRequest('Invalid tag id', 0, $e);
114
+        } catch (TagNotFoundException $e) {
115
+            throw new NotFound('Tag with id ' . $name . ' not found', 0, $e);
116
+        }
117
+    }
118
+
119
+    function getChildren() {
120
+        $visibilityFilter = true;
121
+        if ($this->isAdmin()) {
122
+            $visibilityFilter = null;
123
+        }
124
+
125
+        $tags = $this->tagManager->getAllTags($visibilityFilter);
126
+        return array_map(function($tag) {
127
+            return $this->makeNode($tag);
128
+        }, $tags);
129
+    }
130
+
131
+    /**
132
+     * @param string $name
133
+     */
134
+    function childExists($name) {
135
+        try {
136
+            $tag = $this->tagManager->getTagsByIds([$name]);
137
+            $tag = current($tag);
138
+            if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
139
+                return false;
140
+            }
141
+            return true;
142
+        } catch (\InvalidArgumentException $e) {
143
+            throw new BadRequest('Invalid tag id', 0, $e);
144
+        } catch (TagNotFoundException $e) {
145
+            return false;
146
+        }
147
+    }
148
+
149
+    function delete() {
150
+        throw new Forbidden('Permission denied to delete this collection');
151
+    }
152
+
153
+    function getName() {
154
+        return 'systemtags';
155
+    }
156
+
157
+    function setName($name) {
158
+        throw new Forbidden('Permission denied to rename this collection');
159
+    }
160
+
161
+    /**
162
+     * Returns the last modification time, as a unix timestamp
163
+     *
164
+     * @return int
165
+     */
166
+    function getLastModified() {
167
+        return null;
168
+    }
169
+
170
+    /**
171
+     * Create a sabre node for the given system tag
172
+     *
173
+     * @param ISystemTag $tag
174
+     *
175
+     * @return SystemTagNode
176
+     */
177
+    private function makeNode(ISystemTag $tag) {
178
+        return new SystemTagNode($tag, $this->userSession->getUser(), $this->isAdmin(), $this->tagManager);
179
+    }
180 180
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -106,13 +106,13 @@
 block discarded – undo
106 106
 			$tag = $this->tagManager->getTagsByIds([$name]);
107 107
 			$tag = current($tag);
108 108
 			if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
109
-				throw new NotFound('Tag with id ' . $name . ' not found');
109
+				throw new NotFound('Tag with id '.$name.' not found');
110 110
 			}
111 111
 			return $this->makeNode($tag);
112 112
 		} catch (\InvalidArgumentException $e) {
113 113
 			throw new BadRequest('Invalid tag id', 0, $e);
114 114
 		} catch (TagNotFoundException $e) {
115
-			throw new NotFound('Tag with id ' . $name . ' not found', 0, $e);
115
+			throw new NotFound('Tag with id '.$name.' not found', 0, $e);
116 116
 		}
117 117
 	}
118 118
 
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php 2 patches
Indentation   +132 added lines, -132 removed lines patch added patch discarded remove patch
@@ -39,136 +39,136 @@
 block discarded – undo
39 39
  */
40 40
 class SystemTagsObjectTypeCollection implements ICollection {
41 41
 
42
-	/**
43
-	 * @var string
44
-	 */
45
-	private $objectType;
46
-
47
-	/**
48
-	 * @var ISystemTagManager
49
-	 */
50
-	private $tagManager;
51
-
52
-	/**
53
-	 * @var ISystemTagObjectMapper
54
-	 */
55
-	private $tagMapper;
56
-
57
-	/**
58
-	 * @var IGroupManager
59
-	 */
60
-	private $groupManager;
61
-
62
-	/**
63
-	 * @var IUserSession
64
-	 */
65
-	private $userSession;
66
-
67
-	/**
68
-	 * @var \Closure
69
-	 **/
70
-	protected $childExistsFunction;
71
-
72
-	/**
73
-	 * Constructor
74
-	 *
75
-	 * @param string $objectType object type
76
-	 * @param ISystemTagManager $tagManager
77
-	 * @param ISystemTagObjectMapper $tagMapper
78
-	 * @param IUserSession $userSession
79
-	 * @param IGroupManager $groupManager
80
-	 * @param \Closure $childExistsFunction
81
-	 */
82
-	public function __construct(
83
-		$objectType, 
84
-		ISystemTagManager $tagManager,
85
-		ISystemTagObjectMapper $tagMapper,
86
-		IUserSession $userSession,
87
-		IGroupManager $groupManager,
88
-		\Closure $childExistsFunction
89
-	) {
90
-		$this->tagManager = $tagManager;
91
-		$this->tagMapper = $tagMapper;
92
-		$this->objectType = $objectType;
93
-		$this->userSession = $userSession;
94
-		$this->groupManager = $groupManager;
95
-		$this->childExistsFunction = $childExistsFunction;
96
-	}
97
-
98
-	/**
99
-	 * @param string $name
100
-	 * @param resource|string $data Initial payload
101
-	 * @return null|string
102
-	 * @throws Forbidden
103
-	 */
104
-	function createFile($name, $data = null) {
105
-		throw new Forbidden('Permission denied to create nodes');
106
-	}
107
-
108
-	/**
109
-	 * @param string $name
110
-	 * @throws Forbidden
111
-	 */
112
-	function createDirectory($name) {
113
-		throw new Forbidden('Permission denied to create collections');
114
-	}
115
-
116
-	/**
117
-	 * @param string $objectId
118
-	 * @return SystemTagsObjectMappingCollection
119
-	 * @throws NotFound
120
-	 */
121
-	function getChild($objectId) {
122
-		// make sure the object exists and is reachable
123
-		if(!$this->childExists($objectId)) {
124
-			throw new NotFound('Entity does not exist or is not available');
125
-		}
126
-		return new SystemTagsObjectMappingCollection(
127
-			$objectId,
128
-			$this->objectType,
129
-			$this->userSession->getUser(),
130
-			$this->tagManager,
131
-			$this->tagMapper
132
-		);
133
-	}
134
-
135
-	function getChildren() {
136
-		// do not list object ids
137
-		throw new MethodNotAllowed();
138
-	}
139
-
140
-	/**
141
-	 * Checks if a child-node with the specified name exists
142
-	 *
143
-	 * @param string $name
144
-	 * @return bool
145
-	 */
146
-	function childExists($name) {
147
-		return call_user_func($this->childExistsFunction, $name);
148
-	}
149
-
150
-	function delete() {
151
-		throw new Forbidden('Permission denied to delete this collection');
152
-	}
153
-
154
-	function getName() {
155
-		return $this->objectType;
156
-	}
157
-
158
-	/**
159
-	 * @param string $name
160
-	 * @throws Forbidden
161
-	 */
162
-	function setName($name) {
163
-		throw new Forbidden('Permission denied to rename this collection');
164
-	}
165
-
166
-	/**
167
-	 * Returns the last modification time, as a unix timestamp
168
-	 *
169
-	 * @return int
170
-	 */
171
-	function getLastModified() {
172
-		return null;
173
-	}
42
+    /**
43
+     * @var string
44
+     */
45
+    private $objectType;
46
+
47
+    /**
48
+     * @var ISystemTagManager
49
+     */
50
+    private $tagManager;
51
+
52
+    /**
53
+     * @var ISystemTagObjectMapper
54
+     */
55
+    private $tagMapper;
56
+
57
+    /**
58
+     * @var IGroupManager
59
+     */
60
+    private $groupManager;
61
+
62
+    /**
63
+     * @var IUserSession
64
+     */
65
+    private $userSession;
66
+
67
+    /**
68
+     * @var \Closure
69
+     **/
70
+    protected $childExistsFunction;
71
+
72
+    /**
73
+     * Constructor
74
+     *
75
+     * @param string $objectType object type
76
+     * @param ISystemTagManager $tagManager
77
+     * @param ISystemTagObjectMapper $tagMapper
78
+     * @param IUserSession $userSession
79
+     * @param IGroupManager $groupManager
80
+     * @param \Closure $childExistsFunction
81
+     */
82
+    public function __construct(
83
+        $objectType, 
84
+        ISystemTagManager $tagManager,
85
+        ISystemTagObjectMapper $tagMapper,
86
+        IUserSession $userSession,
87
+        IGroupManager $groupManager,
88
+        \Closure $childExistsFunction
89
+    ) {
90
+        $this->tagManager = $tagManager;
91
+        $this->tagMapper = $tagMapper;
92
+        $this->objectType = $objectType;
93
+        $this->userSession = $userSession;
94
+        $this->groupManager = $groupManager;
95
+        $this->childExistsFunction = $childExistsFunction;
96
+    }
97
+
98
+    /**
99
+     * @param string $name
100
+     * @param resource|string $data Initial payload
101
+     * @return null|string
102
+     * @throws Forbidden
103
+     */
104
+    function createFile($name, $data = null) {
105
+        throw new Forbidden('Permission denied to create nodes');
106
+    }
107
+
108
+    /**
109
+     * @param string $name
110
+     * @throws Forbidden
111
+     */
112
+    function createDirectory($name) {
113
+        throw new Forbidden('Permission denied to create collections');
114
+    }
115
+
116
+    /**
117
+     * @param string $objectId
118
+     * @return SystemTagsObjectMappingCollection
119
+     * @throws NotFound
120
+     */
121
+    function getChild($objectId) {
122
+        // make sure the object exists and is reachable
123
+        if(!$this->childExists($objectId)) {
124
+            throw new NotFound('Entity does not exist or is not available');
125
+        }
126
+        return new SystemTagsObjectMappingCollection(
127
+            $objectId,
128
+            $this->objectType,
129
+            $this->userSession->getUser(),
130
+            $this->tagManager,
131
+            $this->tagMapper
132
+        );
133
+    }
134
+
135
+    function getChildren() {
136
+        // do not list object ids
137
+        throw new MethodNotAllowed();
138
+    }
139
+
140
+    /**
141
+     * Checks if a child-node with the specified name exists
142
+     *
143
+     * @param string $name
144
+     * @return bool
145
+     */
146
+    function childExists($name) {
147
+        return call_user_func($this->childExistsFunction, $name);
148
+    }
149
+
150
+    function delete() {
151
+        throw new Forbidden('Permission denied to delete this collection');
152
+    }
153
+
154
+    function getName() {
155
+        return $this->objectType;
156
+    }
157
+
158
+    /**
159
+     * @param string $name
160
+     * @throws Forbidden
161
+     */
162
+    function setName($name) {
163
+        throw new Forbidden('Permission denied to rename this collection');
164
+    }
165
+
166
+    /**
167
+     * Returns the last modification time, as a unix timestamp
168
+     *
169
+     * @return int
170
+     */
171
+    function getLastModified() {
172
+        return null;
173
+    }
174 174
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -120,7 +120,7 @@
 block discarded – undo
120 120
 	 */
121 121
 	function getChild($objectId) {
122 122
 		// make sure the object exists and is reachable
123
-		if(!$this->childExists($objectId)) {
123
+		if (!$this->childExists($objectId)) {
124 124
 			throw new NotFound('Entity does not exist or is not available');
125 125
 		}
126 126
 		return new SystemTagsObjectMappingCollection(
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagMappingNode.php 2 patches
Indentation   +130 added lines, -130 removed lines patch added patch discarded remove patch
@@ -37,134 +37,134 @@
 block discarded – undo
37 37
  * Mapping node for system tag to object id
38 38
  */
39 39
 class SystemTagMappingNode implements \Sabre\DAV\INode {
40
-	/**
41
-	 * @var ISystemTag
42
-	 */
43
-	protected $tag;
44
-
45
-	/**
46
-	 * @var string
47
-	 */
48
-	private $objectId;
49
-
50
-	/**
51
-	 * @var string
52
-	 */
53
-	private $objectType;
54
-
55
-	/**
56
-	 * User
57
-	 *
58
-	 * @var IUser
59
-	 */
60
-	protected $user;
61
-
62
-	/**
63
-	 * @var ISystemTagManager
64
-	 */
65
-	protected $tagManager;
66
-
67
-	/**
68
-	 * @var ISystemTagObjectMapper
69
-	 */
70
-	private $tagMapper;
71
-
72
-	/**
73
-	 * Sets up the node, expects a full path name
74
-	 *
75
-	 * @param ISystemTag $tag system tag
76
-	 * @param string $objectId
77
-	 * @param string $objectType
78
-	 * @param IUser $user user
79
-	 * @param ISystemTagManager $tagManager
80
-	 * @param ISystemTagObjectMapper $tagMapper
81
-	 */
82
-	public function __construct(
83
-		ISystemTag $tag,
84
-		$objectId,
85
-		$objectType,
86
-		IUser $user,
87
-		ISystemTagManager $tagManager,
88
-		ISystemTagObjectMapper $tagMapper
89
-	) {
90
-		$this->tag = $tag;
91
-		$this->objectId = $objectId;
92
-		$this->objectType = $objectType;
93
-		$this->user = $user;
94
-		$this->tagManager = $tagManager;
95
-		$this->tagMapper = $tagMapper;
96
-	}
97
-
98
-	/**
99
-	 * Returns the object id of the relationship
100
-	 *
101
-	 * @return string object id
102
-	 */
103
-	public function getObjectId() {
104
-		return $this->objectId;
105
-	}
106
-
107
-	/**
108
-	 * Returns the object type of the relationship
109
-	 *
110
-	 * @return string object type
111
-	 */
112
-	public function getObjectType() {
113
-		return $this->objectType;
114
-	}
115
-
116
-	/**
117
-	 * Returns the system tag represented by this node
118
-	 *
119
-	 * @return ISystemTag system tag
120
-	 */
121
-	public function getSystemTag() {
122
-		return $this->tag;
123
-	}
124
-
125
-	/**
126
-	 *  Returns the id of the tag
127
-	 *
128
-	 * @return string
129
-	 */
130
-	public function getName() {
131
-		return $this->tag->getId();
132
-	}
133
-
134
-	/**
135
-	 * Renames the node
136
-	 *
137
-	 * @param string $name The new name
138
-	 *
139
-	 * @throws MethodNotAllowed not allowed to rename node
140
-	 */
141
-	public function setName($name) {
142
-		throw new MethodNotAllowed();
143
-	}
144
-
145
-	/**
146
-	 * Returns null, not supported
147
-	 *
148
-	 */
149
-	public function getLastModified() {
150
-		return null;
151
-	}
152
-
153
-	/**
154
-	 * Delete tag to object association
155
-	 */
156
-	public function delete() {
157
-		try {
158
-			if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
159
-				throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found');
160
-			}
161
-			if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) {
162
-				throw new Forbidden('No permission to unassign tag ' . $this->tag->getId());
163
-			}
164
-			$this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId());
165
-		} catch (TagNotFoundException $e) {
166
-			// can happen if concurrent deletion occurred
167
-			throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
168
-		}
169
-	}
40
+    /**
41
+     * @var ISystemTag
42
+     */
43
+    protected $tag;
44
+
45
+    /**
46
+     * @var string
47
+     */
48
+    private $objectId;
49
+
50
+    /**
51
+     * @var string
52
+     */
53
+    private $objectType;
54
+
55
+    /**
56
+     * User
57
+     *
58
+     * @var IUser
59
+     */
60
+    protected $user;
61
+
62
+    /**
63
+     * @var ISystemTagManager
64
+     */
65
+    protected $tagManager;
66
+
67
+    /**
68
+     * @var ISystemTagObjectMapper
69
+     */
70
+    private $tagMapper;
71
+
72
+    /**
73
+     * Sets up the node, expects a full path name
74
+     *
75
+     * @param ISystemTag $tag system tag
76
+     * @param string $objectId
77
+     * @param string $objectType
78
+     * @param IUser $user user
79
+     * @param ISystemTagManager $tagManager
80
+     * @param ISystemTagObjectMapper $tagMapper
81
+     */
82
+    public function __construct(
83
+        ISystemTag $tag,
84
+        $objectId,
85
+        $objectType,
86
+        IUser $user,
87
+        ISystemTagManager $tagManager,
88
+        ISystemTagObjectMapper $tagMapper
89
+    ) {
90
+        $this->tag = $tag;
91
+        $this->objectId = $objectId;
92
+        $this->objectType = $objectType;
93
+        $this->user = $user;
94
+        $this->tagManager = $tagManager;
95
+        $this->tagMapper = $tagMapper;
96
+    }
97
+
98
+    /**
99
+     * Returns the object id of the relationship
100
+     *
101
+     * @return string object id
102
+     */
103
+    public function getObjectId() {
104
+        return $this->objectId;
105
+    }
106
+
107
+    /**
108
+     * Returns the object type of the relationship
109
+     *
110
+     * @return string object type
111
+     */
112
+    public function getObjectType() {
113
+        return $this->objectType;
114
+    }
115
+
116
+    /**
117
+     * Returns the system tag represented by this node
118
+     *
119
+     * @return ISystemTag system tag
120
+     */
121
+    public function getSystemTag() {
122
+        return $this->tag;
123
+    }
124
+
125
+    /**
126
+     *  Returns the id of the tag
127
+     *
128
+     * @return string
129
+     */
130
+    public function getName() {
131
+        return $this->tag->getId();
132
+    }
133
+
134
+    /**
135
+     * Renames the node
136
+     *
137
+     * @param string $name The new name
138
+     *
139
+     * @throws MethodNotAllowed not allowed to rename node
140
+     */
141
+    public function setName($name) {
142
+        throw new MethodNotAllowed();
143
+    }
144
+
145
+    /**
146
+     * Returns null, not supported
147
+     *
148
+     */
149
+    public function getLastModified() {
150
+        return null;
151
+    }
152
+
153
+    /**
154
+     * Delete tag to object association
155
+     */
156
+    public function delete() {
157
+        try {
158
+            if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
159
+                throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found');
160
+            }
161
+            if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) {
162
+                throw new Forbidden('No permission to unassign tag ' . $this->tag->getId());
163
+            }
164
+            $this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId());
165
+        } catch (TagNotFoundException $e) {
166
+            // can happen if concurrent deletion occurred
167
+            throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
168
+        }
169
+    }
170 170
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -156,15 +156,15 @@
 block discarded – undo
156 156
 	public function delete() {
157 157
 		try {
158 158
 			if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) {
159
-				throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found');
159
+				throw new NotFound('Tag with id '.$this->tag->getId().' not found');
160 160
 			}
161 161
 			if (!$this->tagManager->canUserAssignTag($this->tag, $this->user)) {
162
-				throw new Forbidden('No permission to unassign tag ' . $this->tag->getId());
162
+				throw new Forbidden('No permission to unassign tag '.$this->tag->getId());
163 163
 			}
164 164
 			$this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId());
165 165
 		} catch (TagNotFoundException $e) {
166 166
 			// can happen if concurrent deletion occurred
167
-			throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
167
+			throw new NotFound('Tag with id '.$this->tag->getId().' not found', 0, $e);
168 168
 		}
169 169
 	}
170 170
 }
Please login to merge, or discard this patch.