Passed
Push — master ( 024ed9...a2a964 )
by Roeland
15:08 queued 11s
created
apps/dav/lib/CardDAV/SyncService.php 1 patch
Indentation   +295 added lines, -295 removed lines patch added patch discarded remove patch
@@ -42,299 +42,299 @@
 block discarded – undo
42 42
 
43 43
 class SyncService {
44 44
 
45
-	/** @var CardDavBackend */
46
-	private $backend;
47
-
48
-	/** @var IUserManager */
49
-	private $userManager;
50
-
51
-	/** @var ILogger */
52
-	private $logger;
53
-
54
-	/** @var array */
55
-	private $localSystemAddressBook;
56
-
57
-	/** @var Converter */
58
-	private $converter;
59
-
60
-	/** @var string */
61
-	protected $certPath;
62
-
63
-	/**
64
-	 * SyncService constructor.
65
-	 *
66
-	 * @param CardDavBackend $backend
67
-	 * @param IUserManager $userManager
68
-	 * @param ILogger $logger
69
-	 * @param AccountManager $accountManager
70
-	 */
71
-	public function __construct(CardDavBackend $backend, IUserManager $userManager, ILogger $logger, Converter $converter) {
72
-		$this->backend = $backend;
73
-		$this->userManager = $userManager;
74
-		$this->logger = $logger;
75
-		$this->converter = $converter;
76
-		$this->certPath = '';
77
-	}
78
-
79
-	/**
80
-	 * @param string $url
81
-	 * @param string $userName
82
-	 * @param string $addressBookUrl
83
-	 * @param string $sharedSecret
84
-	 * @param string $syncToken
85
-	 * @param int $targetBookId
86
-	 * @param string $targetPrincipal
87
-	 * @param array $targetProperties
88
-	 * @return string
89
-	 * @throws \Exception
90
-	 */
91
-	public function syncRemoteAddressBook($url, $userName, $addressBookUrl, $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetProperties) {
92
-		// 1. create addressbook
93
-		$book = $this->ensureSystemAddressBookExists($targetPrincipal, $targetBookId, $targetProperties);
94
-		$addressBookId = $book['id'];
95
-
96
-		// 2. query changes
97
-		try {
98
-			$response = $this->requestSyncReport($url, $userName, $addressBookUrl, $sharedSecret, $syncToken);
99
-		} catch (ClientHttpException $ex) {
100
-			if ($ex->getCode() === Http::STATUS_UNAUTHORIZED) {
101
-				// remote server revoked access to the address book, remove it
102
-				$this->backend->deleteAddressBook($addressBookId);
103
-				$this->logger->info('Authorization failed, remove address book: ' . $url, ['app' => 'dav']);
104
-				throw $ex;
105
-			}
106
-		}
107
-
108
-		// 3. apply changes
109
-		// TODO: use multi-get for download
110
-		foreach ($response['response'] as $resource => $status) {
111
-			$cardUri = basename($resource);
112
-			if (isset($status[200])) {
113
-				$vCard = $this->download($url, $userName, $sharedSecret, $resource);
114
-				$existingCard = $this->backend->getCard($addressBookId, $cardUri);
115
-				if ($existingCard === false) {
116
-					$this->backend->createCard($addressBookId, $cardUri, $vCard['body']);
117
-				} else {
118
-					$this->backend->updateCard($addressBookId, $cardUri, $vCard['body']);
119
-				}
120
-			} else {
121
-				$this->backend->deleteCard($addressBookId, $cardUri);
122
-			}
123
-		}
124
-
125
-		return $response['token'];
126
-	}
127
-
128
-	/**
129
-	 * @param string $principal
130
-	 * @param string $id
131
-	 * @param array $properties
132
-	 * @return array|null
133
-	 * @throws \Sabre\DAV\Exception\BadRequest
134
-	 */
135
-	public function ensureSystemAddressBookExists($principal, $id, $properties) {
136
-		$book = $this->backend->getAddressBooksByUri($principal, $id);
137
-		if (!is_null($book)) {
138
-			return $book;
139
-		}
140
-		$this->backend->createAddressBook($principal, $id, $properties);
141
-
142
-		return $this->backend->getAddressBooksByUri($principal, $id);
143
-	}
144
-
145
-	/**
146
-	 * Check if there is a valid certPath we should use
147
-	 *
148
-	 * @return string
149
-	 */
150
-	protected function getCertPath() {
151
-
152
-		// we already have a valid certPath
153
-		if ($this->certPath !== '') {
154
-			return $this->certPath;
155
-		}
156
-
157
-		$certManager = \OC::$server->getCertificateManager();
158
-		$certPath = $certManager->getAbsoluteBundlePath();
159
-		if (file_exists($certPath)) {
160
-			$this->certPath = $certPath;
161
-		}
162
-
163
-		return $this->certPath;
164
-	}
165
-
166
-	/**
167
-	 * @param string $url
168
-	 * @param string $userName
169
-	 * @param string $addressBookUrl
170
-	 * @param string $sharedSecret
171
-	 * @return Client
172
-	 */
173
-	protected function getClient($url, $userName, $sharedSecret) {
174
-		$settings = [
175
-			'baseUri' => $url . '/',
176
-			'userName' => $userName,
177
-			'password' => $sharedSecret,
178
-		];
179
-		$client = new Client($settings);
180
-		$certPath = $this->getCertPath();
181
-		$client->setThrowExceptions(true);
182
-
183
-		if ($certPath !== '' && strpos($url, 'http://') !== 0) {
184
-			$client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
185
-		}
186
-
187
-		return $client;
188
-	}
189
-
190
-	/**
191
-	 * @param string $url
192
-	 * @param string $userName
193
-	 * @param string $addressBookUrl
194
-	 * @param string $sharedSecret
195
-	 * @param string $syncToken
196
-	 * @return array
197
-	 */
198
-	protected function requestSyncReport($url, $userName, $addressBookUrl, $sharedSecret, $syncToken) {
199
-		$client = $this->getClient($url, $userName, $sharedSecret);
200
-
201
-		$body = $this->buildSyncCollectionRequestBody($syncToken);
202
-
203
-		$response = $client->request('REPORT', $addressBookUrl, $body, [
204
-			'Content-Type' => 'application/xml'
205
-		]);
206
-
207
-		return $this->parseMultiStatus($response['body']);
208
-	}
209
-
210
-	/**
211
-	 * @param string $url
212
-	 * @param string $userName
213
-	 * @param string $sharedSecret
214
-	 * @param string $resourcePath
215
-	 * @return array
216
-	 */
217
-	protected function download($url, $userName, $sharedSecret, $resourcePath) {
218
-		$client = $this->getClient($url, $userName, $sharedSecret);
219
-		return $client->request('GET', $resourcePath);
220
-	}
221
-
222
-	/**
223
-	 * @param string|null $syncToken
224
-	 * @return string
225
-	 */
226
-	private function buildSyncCollectionRequestBody($syncToken) {
227
-		$dom = new \DOMDocument('1.0', 'UTF-8');
228
-		$dom->formatOutput = true;
229
-		$root = $dom->createElementNS('DAV:', 'd:sync-collection');
230
-		$sync = $dom->createElement('d:sync-token', $syncToken);
231
-		$prop = $dom->createElement('d:prop');
232
-		$cont = $dom->createElement('d:getcontenttype');
233
-		$etag = $dom->createElement('d:getetag');
234
-
235
-		$prop->appendChild($cont);
236
-		$prop->appendChild($etag);
237
-		$root->appendChild($sync);
238
-		$root->appendChild($prop);
239
-		$dom->appendChild($root);
240
-		return $dom->saveXML();
241
-	}
242
-
243
-	/**
244
-	 * @param string $body
245
-	 * @return array
246
-	 * @throws \Sabre\Xml\ParseException
247
-	 */
248
-	private function parseMultiStatus($body) {
249
-		$xml = new Service();
250
-
251
-		/** @var MultiStatus $multiStatus */
252
-		$multiStatus = $xml->expect('{DAV:}multistatus', $body);
253
-
254
-		$result = [];
255
-		foreach ($multiStatus->getResponses() as $response) {
256
-			$result[$response->getHref()] = $response->getResponseProperties();
257
-		}
258
-
259
-		return ['response' => $result, 'token' => $multiStatus->getSyncToken()];
260
-	}
261
-
262
-	/**
263
-	 * @param IUser $user
264
-	 */
265
-	public function updateUser(IUser $user) {
266
-		$systemAddressBook = $this->getLocalSystemAddressBook();
267
-		$addressBookId = $systemAddressBook['id'];
268
-		$name = $user->getBackendClassName();
269
-		$userId = $user->getUID();
270
-
271
-		$cardId = "$name:$userId.vcf";
272
-		$card = $this->backend->getCard($addressBookId, $cardId);
273
-		if ($user->isEnabled()) {
274
-			if ($card === false) {
275
-				$vCard = $this->converter->createCardFromUser($user);
276
-				if ($vCard !== null) {
277
-					$this->backend->createCard($addressBookId, $cardId, $vCard->serialize());
278
-				}
279
-			} else {
280
-				$vCard = $this->converter->createCardFromUser($user);
281
-				if (is_null($vCard)) {
282
-					$this->backend->deleteCard($addressBookId, $cardId);
283
-				} else {
284
-					$this->backend->updateCard($addressBookId, $cardId, $vCard->serialize());
285
-				}
286
-			}
287
-		} else {
288
-			$this->backend->deleteCard($addressBookId, $cardId);
289
-		}
290
-	}
291
-
292
-	/**
293
-	 * @param IUser|string $userOrCardId
294
-	 */
295
-	public function deleteUser($userOrCardId) {
296
-		$systemAddressBook = $this->getLocalSystemAddressBook();
297
-		if ($userOrCardId instanceof IUser) {
298
-			$name = $userOrCardId->getBackendClassName();
299
-			$userId = $userOrCardId->getUID();
300
-
301
-			$userOrCardId = "$name:$userId.vcf";
302
-		}
303
-		$this->backend->deleteCard($systemAddressBook['id'], $userOrCardId);
304
-	}
305
-
306
-	/**
307
-	 * @return array|null
308
-	 */
309
-	public function getLocalSystemAddressBook() {
310
-		if (is_null($this->localSystemAddressBook)) {
311
-			$systemPrincipal = "principals/system/system";
312
-			$this->localSystemAddressBook = $this->ensureSystemAddressBookExists($systemPrincipal, 'system', [
313
-				'{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance'
314
-			]);
315
-		}
316
-
317
-		return $this->localSystemAddressBook;
318
-	}
319
-
320
-	public function syncInstance(\Closure $progressCallback = null) {
321
-		$systemAddressBook = $this->getLocalSystemAddressBook();
322
-		$this->userManager->callForAllUsers(function ($user) use ($systemAddressBook, $progressCallback) {
323
-			$this->updateUser($user);
324
-			if (!is_null($progressCallback)) {
325
-				$progressCallback();
326
-			}
327
-		});
328
-
329
-		// remove no longer existing
330
-		$allCards = $this->backend->getCards($systemAddressBook['id']);
331
-		foreach ($allCards as $card) {
332
-			$vCard = Reader::read($card['carddata']);
333
-			$uid = $vCard->UID->getValue();
334
-			// load backend and see if user exists
335
-			if (!$this->userManager->userExists($uid)) {
336
-				$this->deleteUser($card['uri']);
337
-			}
338
-		}
339
-	}
45
+    /** @var CardDavBackend */
46
+    private $backend;
47
+
48
+    /** @var IUserManager */
49
+    private $userManager;
50
+
51
+    /** @var ILogger */
52
+    private $logger;
53
+
54
+    /** @var array */
55
+    private $localSystemAddressBook;
56
+
57
+    /** @var Converter */
58
+    private $converter;
59
+
60
+    /** @var string */
61
+    protected $certPath;
62
+
63
+    /**
64
+     * SyncService constructor.
65
+     *
66
+     * @param CardDavBackend $backend
67
+     * @param IUserManager $userManager
68
+     * @param ILogger $logger
69
+     * @param AccountManager $accountManager
70
+     */
71
+    public function __construct(CardDavBackend $backend, IUserManager $userManager, ILogger $logger, Converter $converter) {
72
+        $this->backend = $backend;
73
+        $this->userManager = $userManager;
74
+        $this->logger = $logger;
75
+        $this->converter = $converter;
76
+        $this->certPath = '';
77
+    }
78
+
79
+    /**
80
+     * @param string $url
81
+     * @param string $userName
82
+     * @param string $addressBookUrl
83
+     * @param string $sharedSecret
84
+     * @param string $syncToken
85
+     * @param int $targetBookId
86
+     * @param string $targetPrincipal
87
+     * @param array $targetProperties
88
+     * @return string
89
+     * @throws \Exception
90
+     */
91
+    public function syncRemoteAddressBook($url, $userName, $addressBookUrl, $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetProperties) {
92
+        // 1. create addressbook
93
+        $book = $this->ensureSystemAddressBookExists($targetPrincipal, $targetBookId, $targetProperties);
94
+        $addressBookId = $book['id'];
95
+
96
+        // 2. query changes
97
+        try {
98
+            $response = $this->requestSyncReport($url, $userName, $addressBookUrl, $sharedSecret, $syncToken);
99
+        } catch (ClientHttpException $ex) {
100
+            if ($ex->getCode() === Http::STATUS_UNAUTHORIZED) {
101
+                // remote server revoked access to the address book, remove it
102
+                $this->backend->deleteAddressBook($addressBookId);
103
+                $this->logger->info('Authorization failed, remove address book: ' . $url, ['app' => 'dav']);
104
+                throw $ex;
105
+            }
106
+        }
107
+
108
+        // 3. apply changes
109
+        // TODO: use multi-get for download
110
+        foreach ($response['response'] as $resource => $status) {
111
+            $cardUri = basename($resource);
112
+            if (isset($status[200])) {
113
+                $vCard = $this->download($url, $userName, $sharedSecret, $resource);
114
+                $existingCard = $this->backend->getCard($addressBookId, $cardUri);
115
+                if ($existingCard === false) {
116
+                    $this->backend->createCard($addressBookId, $cardUri, $vCard['body']);
117
+                } else {
118
+                    $this->backend->updateCard($addressBookId, $cardUri, $vCard['body']);
119
+                }
120
+            } else {
121
+                $this->backend->deleteCard($addressBookId, $cardUri);
122
+            }
123
+        }
124
+
125
+        return $response['token'];
126
+    }
127
+
128
+    /**
129
+     * @param string $principal
130
+     * @param string $id
131
+     * @param array $properties
132
+     * @return array|null
133
+     * @throws \Sabre\DAV\Exception\BadRequest
134
+     */
135
+    public function ensureSystemAddressBookExists($principal, $id, $properties) {
136
+        $book = $this->backend->getAddressBooksByUri($principal, $id);
137
+        if (!is_null($book)) {
138
+            return $book;
139
+        }
140
+        $this->backend->createAddressBook($principal, $id, $properties);
141
+
142
+        return $this->backend->getAddressBooksByUri($principal, $id);
143
+    }
144
+
145
+    /**
146
+     * Check if there is a valid certPath we should use
147
+     *
148
+     * @return string
149
+     */
150
+    protected function getCertPath() {
151
+
152
+        // we already have a valid certPath
153
+        if ($this->certPath !== '') {
154
+            return $this->certPath;
155
+        }
156
+
157
+        $certManager = \OC::$server->getCertificateManager();
158
+        $certPath = $certManager->getAbsoluteBundlePath();
159
+        if (file_exists($certPath)) {
160
+            $this->certPath = $certPath;
161
+        }
162
+
163
+        return $this->certPath;
164
+    }
165
+
166
+    /**
167
+     * @param string $url
168
+     * @param string $userName
169
+     * @param string $addressBookUrl
170
+     * @param string $sharedSecret
171
+     * @return Client
172
+     */
173
+    protected function getClient($url, $userName, $sharedSecret) {
174
+        $settings = [
175
+            'baseUri' => $url . '/',
176
+            'userName' => $userName,
177
+            'password' => $sharedSecret,
178
+        ];
179
+        $client = new Client($settings);
180
+        $certPath = $this->getCertPath();
181
+        $client->setThrowExceptions(true);
182
+
183
+        if ($certPath !== '' && strpos($url, 'http://') !== 0) {
184
+            $client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
185
+        }
186
+
187
+        return $client;
188
+    }
189
+
190
+    /**
191
+     * @param string $url
192
+     * @param string $userName
193
+     * @param string $addressBookUrl
194
+     * @param string $sharedSecret
195
+     * @param string $syncToken
196
+     * @return array
197
+     */
198
+    protected function requestSyncReport($url, $userName, $addressBookUrl, $sharedSecret, $syncToken) {
199
+        $client = $this->getClient($url, $userName, $sharedSecret);
200
+
201
+        $body = $this->buildSyncCollectionRequestBody($syncToken);
202
+
203
+        $response = $client->request('REPORT', $addressBookUrl, $body, [
204
+            'Content-Type' => 'application/xml'
205
+        ]);
206
+
207
+        return $this->parseMultiStatus($response['body']);
208
+    }
209
+
210
+    /**
211
+     * @param string $url
212
+     * @param string $userName
213
+     * @param string $sharedSecret
214
+     * @param string $resourcePath
215
+     * @return array
216
+     */
217
+    protected function download($url, $userName, $sharedSecret, $resourcePath) {
218
+        $client = $this->getClient($url, $userName, $sharedSecret);
219
+        return $client->request('GET', $resourcePath);
220
+    }
221
+
222
+    /**
223
+     * @param string|null $syncToken
224
+     * @return string
225
+     */
226
+    private function buildSyncCollectionRequestBody($syncToken) {
227
+        $dom = new \DOMDocument('1.0', 'UTF-8');
228
+        $dom->formatOutput = true;
229
+        $root = $dom->createElementNS('DAV:', 'd:sync-collection');
230
+        $sync = $dom->createElement('d:sync-token', $syncToken);
231
+        $prop = $dom->createElement('d:prop');
232
+        $cont = $dom->createElement('d:getcontenttype');
233
+        $etag = $dom->createElement('d:getetag');
234
+
235
+        $prop->appendChild($cont);
236
+        $prop->appendChild($etag);
237
+        $root->appendChild($sync);
238
+        $root->appendChild($prop);
239
+        $dom->appendChild($root);
240
+        return $dom->saveXML();
241
+    }
242
+
243
+    /**
244
+     * @param string $body
245
+     * @return array
246
+     * @throws \Sabre\Xml\ParseException
247
+     */
248
+    private function parseMultiStatus($body) {
249
+        $xml = new Service();
250
+
251
+        /** @var MultiStatus $multiStatus */
252
+        $multiStatus = $xml->expect('{DAV:}multistatus', $body);
253
+
254
+        $result = [];
255
+        foreach ($multiStatus->getResponses() as $response) {
256
+            $result[$response->getHref()] = $response->getResponseProperties();
257
+        }
258
+
259
+        return ['response' => $result, 'token' => $multiStatus->getSyncToken()];
260
+    }
261
+
262
+    /**
263
+     * @param IUser $user
264
+     */
265
+    public function updateUser(IUser $user) {
266
+        $systemAddressBook = $this->getLocalSystemAddressBook();
267
+        $addressBookId = $systemAddressBook['id'];
268
+        $name = $user->getBackendClassName();
269
+        $userId = $user->getUID();
270
+
271
+        $cardId = "$name:$userId.vcf";
272
+        $card = $this->backend->getCard($addressBookId, $cardId);
273
+        if ($user->isEnabled()) {
274
+            if ($card === false) {
275
+                $vCard = $this->converter->createCardFromUser($user);
276
+                if ($vCard !== null) {
277
+                    $this->backend->createCard($addressBookId, $cardId, $vCard->serialize());
278
+                }
279
+            } else {
280
+                $vCard = $this->converter->createCardFromUser($user);
281
+                if (is_null($vCard)) {
282
+                    $this->backend->deleteCard($addressBookId, $cardId);
283
+                } else {
284
+                    $this->backend->updateCard($addressBookId, $cardId, $vCard->serialize());
285
+                }
286
+            }
287
+        } else {
288
+            $this->backend->deleteCard($addressBookId, $cardId);
289
+        }
290
+    }
291
+
292
+    /**
293
+     * @param IUser|string $userOrCardId
294
+     */
295
+    public function deleteUser($userOrCardId) {
296
+        $systemAddressBook = $this->getLocalSystemAddressBook();
297
+        if ($userOrCardId instanceof IUser) {
298
+            $name = $userOrCardId->getBackendClassName();
299
+            $userId = $userOrCardId->getUID();
300
+
301
+            $userOrCardId = "$name:$userId.vcf";
302
+        }
303
+        $this->backend->deleteCard($systemAddressBook['id'], $userOrCardId);
304
+    }
305
+
306
+    /**
307
+     * @return array|null
308
+     */
309
+    public function getLocalSystemAddressBook() {
310
+        if (is_null($this->localSystemAddressBook)) {
311
+            $systemPrincipal = "principals/system/system";
312
+            $this->localSystemAddressBook = $this->ensureSystemAddressBookExists($systemPrincipal, 'system', [
313
+                '{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance'
314
+            ]);
315
+        }
316
+
317
+        return $this->localSystemAddressBook;
318
+    }
319
+
320
+    public function syncInstance(\Closure $progressCallback = null) {
321
+        $systemAddressBook = $this->getLocalSystemAddressBook();
322
+        $this->userManager->callForAllUsers(function ($user) use ($systemAddressBook, $progressCallback) {
323
+            $this->updateUser($user);
324
+            if (!is_null($progressCallback)) {
325
+                $progressCallback();
326
+            }
327
+        });
328
+
329
+        // remove no longer existing
330
+        $allCards = $this->backend->getCards($systemAddressBook['id']);
331
+        foreach ($allCards as $card) {
332
+            $vCard = Reader::read($card['carddata']);
333
+            $uid = $vCard->UID->getValue();
334
+            // load backend and see if user exists
335
+            if (!$this->userManager->userExists($uid)) {
336
+                $this->deleteUser($card['uri']);
337
+            }
338
+        }
339
+    }
340 340
 }
Please login to merge, or discard this patch.
apps/dav/lib/CardDAV/Converter.php 1 patch
Indentation   +94 added lines, -94 removed lines patch added patch discarded remove patch
@@ -36,98 +36,98 @@
 block discarded – undo
36 36
 
37 37
 class Converter {
38 38
 
39
-	/** @var IAccountManager */
40
-	private $accountManager;
41
-
42
-	public function __construct(IAccountManager $accountManager) {
43
-		$this->accountManager = $accountManager;
44
-	}
45
-
46
-	public function createCardFromUser(IUser $user): ?VCard {
47
-		$userProperties = $this->accountManager->getAccount($user)->getProperties();
48
-
49
-		$uid = $user->getUID();
50
-		$cloudId = $user->getCloudId();
51
-		$image = $this->getAvatarImage($user);
52
-
53
-		$vCard = new VCard();
54
-		$vCard->VERSION = '3.0';
55
-		$vCard->UID = $uid;
56
-
57
-		$publish = false;
58
-
59
-		foreach ($userProperties as $property) {
60
-			$shareWithTrustedServers =
61
-				$property->getScope() === IAccountManager::SCOPE_FEDERATED ||
62
-				$property->getScope() === IAccountManager::SCOPE_PUBLISHED;
63
-
64
-			$emptyValue = $property->getValue() === '';
65
-
66
-			if ($shareWithTrustedServers && !$emptyValue) {
67
-				$publish = true;
68
-				switch ($property->getName()) {
69
-					case IAccountManager::PROPERTY_DISPLAYNAME:
70
-						$vCard->add(new Text($vCard, 'FN', $property->getValue()));
71
-						$vCard->add(new Text($vCard, 'N', $this->splitFullName($property->getValue())));
72
-						break;
73
-					case IAccountManager::PROPERTY_AVATAR:
74
-						if ($image !== null) {
75
-							$vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]);
76
-						}
77
-						break;
78
-					case IAccountManager::PROPERTY_EMAIL:
79
-						$vCard->add(new Text($vCard, 'EMAIL', $property->getValue(), ['TYPE' => 'OTHER']));
80
-						break;
81
-					case IAccountManager::PROPERTY_WEBSITE:
82
-						$vCard->add(new Text($vCard, 'URL', $property->getValue()));
83
-						break;
84
-					case IAccountManager::PROPERTY_PHONE:
85
-						$vCard->add(new Text($vCard, 'TEL', $property->getValue(), ['TYPE' => 'OTHER']));
86
-						break;
87
-					case IAccountManager::PROPERTY_ADDRESS:
88
-						$vCard->add(new Text($vCard, 'ADR', $property->getValue(), ['TYPE' => 'OTHER']));
89
-						break;
90
-					case IAccountManager::PROPERTY_TWITTER:
91
-						$vCard->add(new Text($vCard, 'X-SOCIALPROFILE', $property->getValue(), ['TYPE' => 'TWITTER']));
92
-						break;
93
-				}
94
-			}
95
-		}
96
-
97
-		if ($publish && !empty($cloudId)) {
98
-			$vCard->add(new Text($vCard, 'CLOUD', $cloudId));
99
-			$vCard->validate();
100
-			return $vCard;
101
-		}
102
-
103
-		return null;
104
-	}
105
-
106
-	public function splitFullName(string $fullName): array {
107
-		// Very basic western style parsing. I'm not gonna implement
108
-		// https://github.com/android/platform_packages_providers_contactsprovider/blob/master/src/com/android/providers/contacts/NameSplitter.java ;)
109
-
110
-		$elements = explode(' ', $fullName);
111
-		$result = ['', '', '', '', ''];
112
-		if (count($elements) > 2) {
113
-			$result[0] = implode(' ', array_slice($elements, count($elements) - 1));
114
-			$result[1] = $elements[0];
115
-			$result[2] = implode(' ', array_slice($elements, 1, count($elements) - 2));
116
-		} elseif (count($elements) === 2) {
117
-			$result[0] = $elements[1];
118
-			$result[1] = $elements[0];
119
-		} else {
120
-			$result[0] = $elements[0];
121
-		}
122
-
123
-		return $result;
124
-	}
125
-
126
-	private function getAvatarImage(IUser $user): ?IImage {
127
-		try {
128
-			return $user->getAvatarImage(-1);
129
-		} catch (Exception $ex) {
130
-			return null;
131
-		}
132
-	}
39
+    /** @var IAccountManager */
40
+    private $accountManager;
41
+
42
+    public function __construct(IAccountManager $accountManager) {
43
+        $this->accountManager = $accountManager;
44
+    }
45
+
46
+    public function createCardFromUser(IUser $user): ?VCard {
47
+        $userProperties = $this->accountManager->getAccount($user)->getProperties();
48
+
49
+        $uid = $user->getUID();
50
+        $cloudId = $user->getCloudId();
51
+        $image = $this->getAvatarImage($user);
52
+
53
+        $vCard = new VCard();
54
+        $vCard->VERSION = '3.0';
55
+        $vCard->UID = $uid;
56
+
57
+        $publish = false;
58
+
59
+        foreach ($userProperties as $property) {
60
+            $shareWithTrustedServers =
61
+                $property->getScope() === IAccountManager::SCOPE_FEDERATED ||
62
+                $property->getScope() === IAccountManager::SCOPE_PUBLISHED;
63
+
64
+            $emptyValue = $property->getValue() === '';
65
+
66
+            if ($shareWithTrustedServers && !$emptyValue) {
67
+                $publish = true;
68
+                switch ($property->getName()) {
69
+                    case IAccountManager::PROPERTY_DISPLAYNAME:
70
+                        $vCard->add(new Text($vCard, 'FN', $property->getValue()));
71
+                        $vCard->add(new Text($vCard, 'N', $this->splitFullName($property->getValue())));
72
+                        break;
73
+                    case IAccountManager::PROPERTY_AVATAR:
74
+                        if ($image !== null) {
75
+                            $vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]);
76
+                        }
77
+                        break;
78
+                    case IAccountManager::PROPERTY_EMAIL:
79
+                        $vCard->add(new Text($vCard, 'EMAIL', $property->getValue(), ['TYPE' => 'OTHER']));
80
+                        break;
81
+                    case IAccountManager::PROPERTY_WEBSITE:
82
+                        $vCard->add(new Text($vCard, 'URL', $property->getValue()));
83
+                        break;
84
+                    case IAccountManager::PROPERTY_PHONE:
85
+                        $vCard->add(new Text($vCard, 'TEL', $property->getValue(), ['TYPE' => 'OTHER']));
86
+                        break;
87
+                    case IAccountManager::PROPERTY_ADDRESS:
88
+                        $vCard->add(new Text($vCard, 'ADR', $property->getValue(), ['TYPE' => 'OTHER']));
89
+                        break;
90
+                    case IAccountManager::PROPERTY_TWITTER:
91
+                        $vCard->add(new Text($vCard, 'X-SOCIALPROFILE', $property->getValue(), ['TYPE' => 'TWITTER']));
92
+                        break;
93
+                }
94
+            }
95
+        }
96
+
97
+        if ($publish && !empty($cloudId)) {
98
+            $vCard->add(new Text($vCard, 'CLOUD', $cloudId));
99
+            $vCard->validate();
100
+            return $vCard;
101
+        }
102
+
103
+        return null;
104
+    }
105
+
106
+    public function splitFullName(string $fullName): array {
107
+        // Very basic western style parsing. I'm not gonna implement
108
+        // https://github.com/android/platform_packages_providers_contactsprovider/blob/master/src/com/android/providers/contacts/NameSplitter.java ;)
109
+
110
+        $elements = explode(' ', $fullName);
111
+        $result = ['', '', '', '', ''];
112
+        if (count($elements) > 2) {
113
+            $result[0] = implode(' ', array_slice($elements, count($elements) - 1));
114
+            $result[1] = $elements[0];
115
+            $result[2] = implode(' ', array_slice($elements, 1, count($elements) - 2));
116
+        } elseif (count($elements) === 2) {
117
+            $result[0] = $elements[1];
118
+            $result[1] = $elements[0];
119
+        } else {
120
+            $result[0] = $elements[0];
121
+        }
122
+
123
+        return $result;
124
+    }
125
+
126
+    private function getAvatarImage(IUser $user): ?IImage {
127
+        try {
128
+            return $user->getAvatarImage(-1);
129
+        } catch (Exception $ex) {
130
+            return null;
131
+        }
132
+    }
133 133
 }
Please login to merge, or discard this patch.