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