1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Circles - Bring cloud-users closer together. |
4
|
|
|
* |
5
|
|
|
* This file is licensed under the Affero General Public License version 3 or |
6
|
|
|
* later. See the COPYING file. |
7
|
|
|
* |
8
|
|
|
* @author Maxence Lange <[email protected]> |
9
|
|
|
* @author Vinicius Cubas Brand <[email protected]> |
10
|
|
|
* @author Daniel Tygel <[email protected]> |
11
|
|
|
* |
12
|
|
|
* @copyright 2017 |
13
|
|
|
* @license GNU AGPL version 3 or any later version |
14
|
|
|
* |
15
|
|
|
* This program is free software: you can redistribute it and/or modify |
16
|
|
|
* it under the terms of the GNU Affero General Public License as |
17
|
|
|
* published by the Free Software Foundation, either version 3 of the |
18
|
|
|
* License, or (at your option) any later version. |
19
|
|
|
* |
20
|
|
|
* This program is distributed in the hope that it will be useful, |
21
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
22
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23
|
|
|
* GNU Affero General Public License for more details. |
24
|
|
|
* |
25
|
|
|
* You should have received a copy of the GNU Affero General Public License |
26
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
27
|
|
|
* |
28
|
|
|
*/ |
29
|
|
|
|
30
|
|
|
|
31
|
|
|
namespace OCA\Circles; |
32
|
|
|
|
33
|
|
|
|
34
|
|
|
use Exception; |
35
|
|
|
use OC; |
36
|
|
|
use OC\Files\Cache\Cache; |
37
|
|
|
use OC\Share20\Exception\InvalidShare; |
38
|
|
|
use OC\Share20\Share; |
39
|
|
|
use OC\User\NoUserException; |
40
|
|
|
use OCA\Circles\Api\v1\Circles; |
41
|
|
|
use OCA\Circles\AppInfo\Application; |
42
|
|
|
use OCA\Circles\Db\CircleProviderRequest; |
43
|
|
|
use OCA\Circles\Db\CirclesRequest; |
44
|
|
|
use OCA\Circles\Db\MembersRequest; |
45
|
|
|
use OCA\Circles\Db\TokensRequest; |
46
|
|
|
use OCA\Circles\Model\Circle; |
47
|
|
|
use OCA\Circles\Model\Member; |
48
|
|
|
use OCA\Circles\Service\CirclesService; |
49
|
|
|
use OCA\Circles\Service\ConfigService; |
50
|
|
|
use OCA\Circles\Service\MembersService; |
51
|
|
|
use OCA\Circles\Service\MiscService; |
52
|
|
|
use OCA\Circles\Service\TimezoneService; |
53
|
|
|
use OCP\AppFramework\QueryException; |
54
|
|
|
use OCP\DB\QueryBuilder\IQueryBuilder; |
55
|
|
|
use OCP\Files\Folder; |
56
|
|
|
use OCP\Files\IRootFolder; |
57
|
|
|
use OCP\Files\Node; |
58
|
|
|
use OCP\Files\NotFoundException; |
59
|
|
|
use OCP\IDBConnection; |
60
|
|
|
use OCP\IL10N; |
61
|
|
|
use OCP\ILogger; |
62
|
|
|
use OCP\IURLGenerator; |
63
|
|
|
use OCP\IUserManager; |
64
|
|
|
use OCP\Security\ISecureRandom; |
65
|
|
|
use OCP\Share\Exceptions\IllegalIDChangeException; |
66
|
|
|
use OCP\Share\Exceptions\ShareNotFound; |
67
|
|
|
use OCP\Share\IShare; |
68
|
|
|
use OCP\Share\IShareProvider; |
69
|
|
|
|
70
|
|
|
|
71
|
|
|
class ShareByCircleProvider extends CircleProviderRequest implements IShareProvider { |
72
|
|
|
|
73
|
|
|
|
74
|
|
|
/** @var ILogger */ |
75
|
|
|
private $logger; |
76
|
|
|
|
77
|
|
|
/** @var ISecureRandom */ |
78
|
|
|
private $secureRandom; |
79
|
|
|
|
80
|
|
|
/** @var IUserManager */ |
81
|
|
|
private $userManager; |
82
|
|
|
|
83
|
|
|
/** @var IRootFolder */ |
84
|
|
|
private $rootFolder; |
85
|
|
|
|
86
|
|
|
/** @var IURLGenerator */ |
87
|
|
|
private $urlGenerator; |
88
|
|
|
|
89
|
|
|
/** @var MembersService */ |
90
|
|
|
private $membersService; |
91
|
|
|
|
92
|
|
|
/** @var CirclesRequest */ |
93
|
|
|
private $circlesRequest; |
94
|
|
|
|
95
|
|
|
/** @var MembersRequest */ |
96
|
|
|
private $membersRequest; |
97
|
|
|
|
98
|
|
|
/** @var TokensRequest */ |
99
|
|
|
private $tokensRequest; |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* DefaultShareProvider constructor. |
103
|
|
|
* |
104
|
|
|
* @param IDBConnection $connection |
105
|
|
|
* @param ISecureRandom $secureRandom |
106
|
|
|
* @param IUserManager $userManager |
107
|
|
|
* @param IRootFolder $rootFolder |
108
|
|
|
* @param IL10N $l10n |
109
|
|
|
* @param ILogger $logger |
110
|
|
|
* @param IURLGenerator $urlGenerator |
111
|
|
|
* |
112
|
|
|
* @throws QueryException |
113
|
|
|
*/ |
114
|
|
|
public function __construct( |
115
|
|
|
IDBConnection $connection, ISecureRandom $secureRandom, IUserManager $userManager, |
116
|
|
|
IRootFolder $rootFolder, IL10N $l10n, ILogger $logger, IURLGenerator $urlGenerator |
117
|
|
|
) { |
118
|
|
|
$app = new Application(); |
119
|
|
|
$container = $app->getContainer(); |
120
|
|
|
$configService = $container->query(ConfigService::class); |
121
|
|
|
$miscService = $container->query(MiscService::class); |
122
|
|
|
$timezoneService = $container->query(TimezoneService::class); |
123
|
|
|
|
124
|
|
|
parent::__construct($l10n, $connection, $configService, $timezoneService, $miscService); |
125
|
|
|
|
126
|
|
|
$this->secureRandom = $secureRandom; |
127
|
|
|
$this->userManager = $userManager; |
128
|
|
|
$this->rootFolder = $rootFolder; |
129
|
|
|
$this->logger = $logger; |
130
|
|
|
$this->urlGenerator = $urlGenerator; |
131
|
|
|
$this->membersService = $container->query(MembersService::class); |
132
|
|
|
$this->circlesRequest = $container->query(CirclesRequest::class); |
133
|
|
|
$this->membersRequest = $container->query(MembersRequest::class); |
134
|
|
|
$this->tokensRequest = $container->query(TokensRequest::class); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Return the identifier of this provider. |
140
|
|
|
* |
141
|
|
|
* @return string |
142
|
|
|
*/ |
143
|
|
|
public function identifier() { |
144
|
|
|
return 'ocCircleShare'; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Create a share if it does not exist already. |
150
|
|
|
* |
151
|
|
|
* @param IShare $share |
152
|
|
|
* |
153
|
|
|
* @return IShare The share object |
154
|
|
|
* @throws Exception |
155
|
|
|
*/ |
156
|
|
|
public function create(IShare $share) { |
157
|
|
|
try { |
158
|
|
|
$nodeId = $share->getNode() |
159
|
|
|
->getId(); |
160
|
|
|
|
161
|
|
|
$qb = $this->findShareParentSql($nodeId, $share->getSharedWith()); |
162
|
|
|
$exists = $qb->execute(); |
163
|
|
|
$data = $exists->fetch(); |
164
|
|
|
$exists->closeCursor(); |
165
|
|
|
|
166
|
|
|
if ($data !== false) { |
167
|
|
|
throw $this->errorShareAlreadyExist($share); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
// $share->setToken($this->miscService->uuid(15)); |
171
|
|
|
// if ($this->configService->enforcePasswordProtection()) { |
172
|
|
|
// $share->setPassword($this->miscService->uuid(15)); |
173
|
|
|
// } |
174
|
|
|
|
175
|
|
|
$this->createShare($share); |
176
|
|
|
|
177
|
|
|
$circle = |
178
|
|
|
$this->circlesRequest->getCircle($share->getSharedWith(), $share->getSharedby()); |
179
|
|
|
$circle->getHigherViewer() |
180
|
|
|
->hasToBeMember(); |
181
|
|
|
|
182
|
|
|
Circles::shareToCircle( |
183
|
|
|
$circle->getUniqueId(), 'files', '', |
184
|
|
|
['id' => $share->getId(), 'share' => $this->shareObjectToArray($share)], |
185
|
|
|
'\OCA\Circles\Circles\FileSharingBroadcaster' |
186
|
|
|
); |
187
|
|
|
|
188
|
|
|
return $this->getShareById($share->getId()); |
189
|
|
|
} catch (Exception $e) { |
190
|
|
|
throw $e; |
191
|
|
|
} |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Update a share |
197
|
|
|
* permissions right, owner and initiator |
198
|
|
|
* |
199
|
|
|
* @param IShare $share |
200
|
|
|
* |
201
|
|
|
* @return IShare The share object |
202
|
|
|
*/ |
203
|
|
|
public function update(IShare $share) { |
204
|
|
|
|
205
|
|
|
$qb = $this->getBaseUpdateSql(); |
206
|
|
|
$this->limitToShare($qb, $share->getId()); |
207
|
|
|
$qb->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
208
|
|
|
->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
209
|
|
|
->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())); |
210
|
|
|
$qb->execute(); |
211
|
|
|
|
212
|
|
|
return $share; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Delete a share, and it's children |
218
|
|
|
* |
219
|
|
|
* @param IShare $share |
220
|
|
|
*/ |
221
|
|
|
public function delete(IShare $share) { |
222
|
|
|
$qb = $this->getBaseDeleteSql(); |
223
|
|
|
$this->limitToShareAndChildren($qb, $share->getId()); |
224
|
|
|
$qb->execute(); |
225
|
|
|
|
226
|
|
|
$this->tokensRequest->removeTokenByShareId($share->getId()); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Unshare a file from self as recipient. |
232
|
|
|
* Because every circles share are group shares, we will set permissions to 0 |
233
|
|
|
* |
234
|
|
|
* @param IShare $share |
235
|
|
|
* @param string $userId |
236
|
|
|
*/ |
237
|
|
View Code Duplication |
public function deleteFromSelf(IShare $share, $userId) { |
|
|
|
|
238
|
|
|
$childId = $this->getShareChildId($share, $userId); |
239
|
|
|
|
240
|
|
|
$qb = $this->getBaseUpdateSql(); |
241
|
|
|
$qb->set('permissions', $qb->createNamedParameter(0)); |
242
|
|
|
$this->limitToShare($qb, $childId); |
243
|
|
|
|
244
|
|
|
$qb->execute(); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* Move a share as a recipient. |
250
|
|
|
* |
251
|
|
|
* @param IShare $share |
252
|
|
|
* @param string $userId |
253
|
|
|
* |
254
|
|
|
* @return IShare |
255
|
|
|
* |
256
|
|
|
*/ |
257
|
|
View Code Duplication |
public function move(IShare $share, $userId) { |
|
|
|
|
258
|
|
|
|
259
|
|
|
$childId = $this->getShareChildId($share, $userId); |
260
|
|
|
|
261
|
|
|
$qb = $this->getBaseUpdateSql(); |
262
|
|
|
$qb->set('file_target', $qb->createNamedParameter($share->getTarget())); |
263
|
|
|
$this->limitToShare($qb, $childId); |
264
|
|
|
$qb->execute(); |
265
|
|
|
|
266
|
|
|
return $share; |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* return the child ID of a share |
272
|
|
|
* |
273
|
|
|
* @param IShare $share |
274
|
|
|
* @param string $userId |
275
|
|
|
* |
276
|
|
|
* @return bool |
277
|
|
|
*/ |
278
|
|
|
private function getShareChildId(IShare $share, $userId) { |
279
|
|
|
$qb = $this->getBaseSelectSql($share->getId()); |
280
|
|
|
$this->limitToShareChildren($qb, $userId, $share->getId()); |
281
|
|
|
|
282
|
|
|
$child = $qb->execute(); |
283
|
|
|
$data = $child->fetch(); |
284
|
|
|
$child->closeCursor(); |
285
|
|
|
|
286
|
|
|
if ($data === false) { |
287
|
|
|
return $this->createShareChild($userId, $share); |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
return $data['id']; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Create a child and returns its ID |
296
|
|
|
* |
297
|
|
|
* @param IShare $share |
298
|
|
|
* |
299
|
|
|
* @throws NotFoundException |
300
|
|
|
*/ |
301
|
|
|
private function createShare($share) { |
302
|
|
|
$this->miscService->log( |
303
|
|
|
'Creating share (1/4) - type: ' . $share->getShareType() . ' - token: ' |
304
|
|
|
. $share->getToken() . ' - type: ' . $share->getShareType() . ' - with: ' |
305
|
|
|
. $share->getSharedWith() . ' - permissions: ' . $share->getPermissions(), 0 |
306
|
|
|
); |
307
|
|
|
|
308
|
|
|
$qb = $this->getBaseInsertSql($share); |
309
|
|
|
$this->miscService->log('Share creation (2/4) : ' . json_encode($qb->getSQL()), 0); |
310
|
|
|
|
311
|
|
|
$result = $qb->execute(); |
312
|
|
|
$this->miscService->log('Share creation result (3/4) : ' . json_encode($result), 0); |
313
|
|
|
|
314
|
|
|
$id = $qb->getLastInsertId(); |
315
|
|
|
$this->miscService->log('Share created ID (4/4) : ' . $id, 0); |
316
|
|
|
|
317
|
|
|
try { |
318
|
|
|
$share->setId($id); |
319
|
|
|
} catch (IllegalIDChangeException $e) { |
|
|
|
|
320
|
|
|
} |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
|
324
|
|
|
/** |
325
|
|
|
* Create a child and returns its ID |
326
|
|
|
* |
327
|
|
|
* @param string $userId |
328
|
|
|
* @param IShare $share |
329
|
|
|
* |
330
|
|
|
* @return int |
331
|
|
|
*/ |
332
|
|
|
private function createShareChild($userId, $share) { |
333
|
|
|
$qb = $this->getBaseInsertSql($share); |
334
|
|
|
|
335
|
|
|
$qb->setValue('parent', $qb->createNamedParameter($share->getId())); |
336
|
|
|
$qb->setValue('share_with', $qb->createNamedParameter($userId)); |
337
|
|
|
$qb->execute(); |
338
|
|
|
$id = $qb->getLastInsertId(); |
339
|
|
|
|
340
|
|
|
return (int)$id; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
|
344
|
|
|
/** |
345
|
|
|
* Get all shares by the given user in a folder |
346
|
|
|
* |
347
|
|
|
* @param string $userId |
348
|
|
|
* @param Folder $node |
349
|
|
|
* @param bool $reshares Also get the shares where $user is the owner instead of just the |
350
|
|
|
* shares where $user is the initiator |
351
|
|
|
* |
352
|
|
|
* @return Share[] |
353
|
|
|
*/ |
354
|
|
View Code Duplication |
public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
|
|
|
355
|
|
|
$qb = $this->getBaseSelectSql(); |
356
|
|
|
$this->limitToShareOwner($qb, $userId, true); |
357
|
|
|
$cursor = $qb->execute(); |
358
|
|
|
|
359
|
|
|
$shares = []; |
360
|
|
|
while ($data = $cursor->fetch()) { |
361
|
|
|
$shares[$data['file_source']][] = $this->createShareObject($data); |
362
|
|
|
} |
363
|
|
|
$cursor->closeCursor(); |
364
|
|
|
|
365
|
|
|
return $shares; |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
|
369
|
|
|
/** |
370
|
|
|
* Get all shares by the given user |
371
|
|
|
* |
372
|
|
|
* @param string $userId |
373
|
|
|
* @param int $shareType |
374
|
|
|
* @param Node|null $node |
375
|
|
|
* @param bool $reShares |
376
|
|
|
* @param int $limit The maximum number of shares to be returned, -1 for all shares |
377
|
|
|
* @param int $offset |
378
|
|
|
* |
379
|
|
|
* @return Share[] |
380
|
|
|
*/ |
381
|
|
|
public function getSharesBy($userId, $shareType, $node, $reShares, $limit, $offset) { |
382
|
|
|
$qb = $this->getBaseSelectSql(); |
383
|
|
|
|
384
|
|
|
if ($node === null) { |
385
|
|
|
$this->limitToShareOwner($qb, $userId, $reShares); |
386
|
|
|
} else { |
387
|
|
|
$this->limitToFiles($qb, $node->getId()); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
$this->limitToPage($qb, $limit, $offset); |
391
|
|
|
$cursor = $qb->execute(); |
392
|
|
|
|
393
|
|
|
$shares = []; |
394
|
|
|
while ($data = $cursor->fetch()) { |
395
|
|
|
$shares[] = $this->createShareObject($this->editShareEntry($data)); |
396
|
|
|
} |
397
|
|
|
$cursor->closeCursor(); |
398
|
|
|
|
399
|
|
|
return $shares; |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
|
403
|
|
|
/** |
404
|
|
|
* returns a better formatted string to display more information about |
405
|
|
|
* the circle to the Sharing UI |
406
|
|
|
* |
407
|
|
|
* @param $data |
408
|
|
|
* |
409
|
|
|
* @return array<string,string> |
410
|
|
|
* @throws NoUserException |
411
|
|
|
*/ |
412
|
|
|
private function editShareEntry($data) { |
413
|
|
|
$data['share_with'] = |
414
|
|
|
sprintf( |
415
|
|
|
'%s (%s, %s) [%s]', $data['circle_name'], |
416
|
|
|
Circle::TypeLongString($data['circle_type']), |
417
|
|
|
$this->miscService->getDisplayName($data['circle_owner']), $data['share_with'] |
418
|
|
|
); |
419
|
|
|
|
420
|
|
|
|
421
|
|
|
return $data; |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
|
425
|
|
|
/** |
426
|
|
|
* Get share by its id |
427
|
|
|
* |
428
|
|
|
* @param int $shareId |
429
|
|
|
* @param string|null $recipientId |
430
|
|
|
* |
431
|
|
|
* @return Share |
|
|
|
|
432
|
|
|
* @throws ShareNotFound |
433
|
|
|
*/ |
434
|
|
View Code Duplication |
public function getShareById($shareId, $recipientId = null) { |
|
|
|
|
435
|
|
|
$qb = $this->getBaseSelectSql(); |
436
|
|
|
|
437
|
|
|
$this->limitToShare($qb, $shareId); |
438
|
|
|
|
439
|
|
|
$cursor = $qb->execute(); |
440
|
|
|
$data = $cursor->fetch(); |
441
|
|
|
$cursor->closeCursor(); |
442
|
|
|
|
443
|
|
|
if ($data === false) { |
444
|
|
|
throw new ShareNotFound(); |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
return $this->createShareObject($data); |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
|
451
|
|
|
/** |
452
|
|
|
* Get shares for a given path |
453
|
|
|
* |
454
|
|
|
* @param Node $path |
455
|
|
|
* |
456
|
|
|
* @return IShare[]|null |
|
|
|
|
457
|
|
|
*/ |
458
|
|
|
public function getSharesByPath(Node $path) { |
459
|
|
|
$qb = $this->getBaseSelectSql(); |
460
|
|
|
$this->limitToFiles($qb, [$path->getId()]); |
461
|
|
|
$cursor = $qb->execute(); |
462
|
|
|
|
463
|
|
|
$shares = []; |
464
|
|
|
while ($data = $cursor->fetch()) { |
465
|
|
|
$shares[] = $this->createShareObject($data); |
466
|
|
|
} |
467
|
|
|
$cursor->closeCursor(); |
468
|
|
|
|
469
|
|
|
return $shares; |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* Get shared with the given user |
475
|
|
|
* |
476
|
|
|
* @param string $userId get shares where this user is the recipient |
477
|
|
|
* @param int $shareType |
478
|
|
|
* @param Node|null $node |
479
|
|
|
* @param int $limit The max number of entries returned, -1 for all |
480
|
|
|
* @param int $offset |
481
|
|
|
* |
482
|
|
|
* @return IShare[] |
483
|
|
|
*/ |
484
|
|
|
public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
485
|
|
|
|
486
|
|
|
$shares = $this->getSharedWithCircleMembers($userId, $shareType, $node, $limit, $offset); |
487
|
|
|
|
488
|
|
|
return $shares; |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
|
492
|
|
|
/** |
493
|
|
|
* @param string $userId |
494
|
|
|
* @param $shareType |
495
|
|
|
* @param Node $node |
496
|
|
|
* @param int $limit |
497
|
|
|
* @param int $offset |
498
|
|
|
* |
499
|
|
|
* @return IShare[] |
500
|
|
|
*/ |
501
|
|
|
private function getSharedWithCircleMembers($userId, $shareType, $node, $limit, $offset) { |
502
|
|
|
|
503
|
|
|
$qb = $this->getCompleteSelectSql(); |
504
|
|
|
$this->linkToFileCache($qb, $userId); |
505
|
|
|
$this->limitToPage($qb, $limit, $offset); |
506
|
|
|
|
507
|
|
|
if ($node !== null) { |
508
|
|
|
$this->limitToFiles($qb, [$node->getId()]); |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
$this->linkToMember($qb, $userId, $this->configService->isLinkedGroupsAllowed()); |
512
|
|
|
|
513
|
|
|
$cursor = $qb->execute(); |
514
|
|
|
|
515
|
|
|
$shares = []; |
516
|
|
|
while ($data = $cursor->fetch()) { |
517
|
|
|
self::editShareFromParentEntry($data); |
518
|
|
|
if (self::isAccessibleResult($data)) { |
519
|
|
|
$shares[] = $this->createShareObject($data); |
520
|
|
|
} |
521
|
|
|
} |
522
|
|
|
$cursor->closeCursor(); |
523
|
|
|
|
524
|
|
|
return $shares; |
525
|
|
|
} |
526
|
|
|
|
527
|
|
|
|
528
|
|
|
/** |
529
|
|
|
* Get a share by token |
530
|
|
|
* |
531
|
|
|
* @param string $token |
532
|
|
|
* |
533
|
|
|
* @return IShare |
534
|
|
|
* @throws ShareNotFound |
535
|
|
|
* @deprecated - use local querybuilder lib instead |
536
|
|
|
*/ |
537
|
|
|
public function getShareByToken($token) { |
538
|
|
|
$qb = $this->dbConnection->getQueryBuilder(); |
539
|
|
|
|
540
|
|
|
$this->miscService->log("Opening share by token '#" . $token . "'", 0); |
541
|
|
|
|
542
|
|
|
$cursor = $qb->select('*') |
543
|
|
|
->from('share') |
544
|
|
|
->where( |
545
|
|
|
$qb->expr() |
546
|
|
|
->eq( |
547
|
|
|
'share_type', |
548
|
|
|
$qb->createNamedParameter(\OCP\Share::SHARE_TYPE_CIRCLE) |
549
|
|
|
) |
550
|
|
|
) |
551
|
|
|
->andWhere( |
552
|
|
|
$qb->expr() |
553
|
|
|
->eq('token', $qb->createNamedParameter($token)) |
554
|
|
|
) |
555
|
|
|
->execute(); |
556
|
|
|
|
557
|
|
|
$data = $cursor->fetch(); |
558
|
|
|
|
559
|
|
|
if ($data === false) { |
560
|
|
|
$this->miscService->log('data is false - checking personal token', 0); |
561
|
|
|
try { |
562
|
|
|
$data = $this->getShareByPersonalToken($token); |
563
|
|
|
} catch (Exception $e) { |
564
|
|
|
$this->miscService->log("Share '#" . $token . "' not found.", 0); |
565
|
|
|
throw new ShareNotFound('Share not found', $this->l10n->t('Could not find share')); |
566
|
|
|
} |
567
|
|
|
} |
568
|
|
|
|
569
|
|
|
try { |
570
|
|
|
$share = $this->createShareObject($data); |
571
|
|
|
} catch (InvalidShare $e) { |
|
|
|
|
572
|
|
|
$this->miscService->log( |
573
|
|
|
"Share Object '#" . $token . "' not created. " . json_encode($data), 0 |
574
|
|
|
); |
575
|
|
|
throw new ShareNotFound('Share not found', $this->l10n->t('Could not find share')); |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
return $share; |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
|
582
|
|
|
/** |
583
|
|
|
* @param string $token |
584
|
|
|
* |
585
|
|
|
* @return array |
586
|
|
|
* @throws ShareNotFound |
587
|
|
|
*/ |
588
|
|
|
private function getShareByPersonalToken($token) { |
589
|
|
|
$qb = $this->dbConnection->getQueryBuilder(); |
590
|
|
|
|
591
|
|
|
$qb = $qb->select('s.*') |
592
|
|
|
->selectAlias('ct.password', 'personal_password') |
593
|
|
|
->selectAlias('ct.circle_id', 'personal_circle_id') |
594
|
|
|
->selectAlias('ct.user_id', 'personal_user_id') |
595
|
|
|
->from('share', 's') |
596
|
|
|
->from('circles_tokens', 'ct') |
597
|
|
|
->where( |
598
|
|
|
$qb->expr() |
599
|
|
|
->eq( |
600
|
|
|
's.share_type', |
601
|
|
|
$qb->createNamedParameter(\OCP\Share::SHARE_TYPE_CIRCLE) |
602
|
|
|
) |
603
|
|
|
) |
604
|
|
|
->andWhere( |
605
|
|
|
$qb->expr() |
606
|
|
|
->eq('ct.token', $qb->createNamedParameter($token)) |
607
|
|
|
) |
608
|
|
|
->andWhere( |
609
|
|
|
$qb->expr() |
610
|
|
|
->eq('ct.share_id', 's.id') |
611
|
|
|
); |
612
|
|
|
$cursor = $qb->execute(); |
613
|
|
|
|
614
|
|
|
$data = $cursor->fetch(); |
615
|
|
|
if ($data === false) { |
616
|
|
|
throw new ShareNotFound('personal check not found'); |
617
|
|
|
} |
618
|
|
|
|
619
|
|
|
$member = null; |
620
|
|
|
try { |
621
|
|
|
$member = $this->membersService->getMember( |
622
|
|
|
$data['personal_circle_id'], $data['personal_user_id'], Member::TYPE_MAIL, true |
623
|
|
|
); |
624
|
|
|
} catch (Exception $e) { |
625
|
|
|
try { |
626
|
|
|
$member = $this->membersService->getMember( |
627
|
|
|
$data['personal_circle_id'], $data['personal_user_id'], Member::TYPE_CONTACT, true |
628
|
|
|
); |
629
|
|
|
} catch (Exception $e) { |
|
|
|
|
630
|
|
|
} |
631
|
|
|
} |
632
|
|
|
|
633
|
|
|
if ($member === null || !$member->isLevel(Member::LEVEL_MEMBER)) { |
634
|
|
|
throw new ShareNotFound('invalid token'); |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
return $data; |
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
|
641
|
|
|
/** |
642
|
|
|
* We don't return a thing about children. |
643
|
|
|
* The call to this function is deprecated and should be removed in next release of NC. |
644
|
|
|
* Also, we get the children in the delete() method. |
645
|
|
|
* |
646
|
|
|
* @param IShare $parent |
647
|
|
|
* |
648
|
|
|
* @return array |
649
|
|
|
*/ |
650
|
|
|
public function getChildren(IShare $parent) { |
651
|
|
|
return []; |
652
|
|
|
} |
653
|
|
|
|
654
|
|
|
|
655
|
|
|
/** |
656
|
|
|
* A user is deleted from the system |
657
|
|
|
* So clean up the relevant shares. |
658
|
|
|
* |
659
|
|
|
* @param string $uid |
660
|
|
|
* @param int $shareType |
661
|
|
|
*/ |
662
|
|
|
public function userDeleted($uid, $shareType) { |
663
|
|
|
// TODO: Implement userDeleted() method. |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
|
667
|
|
|
/** |
668
|
|
|
* A group is deleted from the system. |
669
|
|
|
* We handle our own groups. |
670
|
|
|
* |
671
|
|
|
* @param string $gid |
672
|
|
|
*/ |
673
|
|
|
public function groupDeleted($gid) { |
674
|
|
|
return; |
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
|
678
|
|
|
/** |
679
|
|
|
* A user is deleted from a group. |
680
|
|
|
* We handle our own groups. |
681
|
|
|
* |
682
|
|
|
* @param string $uid |
683
|
|
|
* @param string $gid |
684
|
|
|
*/ |
685
|
|
|
public function userDeletedFromGroup($uid, $gid) { |
686
|
|
|
return; |
687
|
|
|
} |
688
|
|
|
|
689
|
|
|
|
690
|
|
|
/** |
691
|
|
|
* Create a share object |
692
|
|
|
* |
693
|
|
|
* @param array $data |
694
|
|
|
* |
695
|
|
|
* @return IShare |
696
|
|
|
*/ |
697
|
|
|
private function createShareObject($data) { |
698
|
|
|
$share = new Share($this->rootFolder, $this->userManager); |
699
|
|
|
$share->setId((int)$data['id']) |
700
|
|
|
->setPermissions((int)$data['permissions']) |
701
|
|
|
->setNodeType($data['item_type']); |
702
|
|
|
|
703
|
|
|
if (($password = $this->get('personal_password', $data, '')) !== '') { |
704
|
|
|
$share->setPassword($this->get('personal_password', $data, '')); |
705
|
|
|
} else if (($password = $this->get('password', $data, '')) !== '') { |
706
|
|
|
$share->setPassword($this->get('password', $data, '')); |
707
|
|
|
} |
708
|
|
|
|
709
|
|
|
$share->setNodeId((int)$data['file_source']) |
710
|
|
|
->setTarget($data['file_target']); |
711
|
|
|
|
712
|
|
|
$this->assignShareObjectSharesProperties($share, $data); |
713
|
|
|
$this->assignShareObjectPropertiesFromParent($share, $data); |
714
|
|
|
|
715
|
|
|
$share->setProviderId($this->identifier()); |
716
|
|
|
|
717
|
|
|
return $share; |
718
|
|
|
} |
719
|
|
|
|
720
|
|
|
|
721
|
|
|
/** |
722
|
|
|
* @param IShare $share |
723
|
|
|
* @param $data |
724
|
|
|
*/ |
725
|
|
|
private function assignShareObjectPropertiesFromParent(IShare &$share, $data) { |
726
|
|
|
if (isset($data['f_permissions'])) { |
727
|
|
|
$entryData = $data; |
728
|
|
|
$entryData['permissions'] = $entryData['f_permissions']; |
729
|
|
|
$entryData['parent'] = $entryData['f_parent']; |
730
|
|
|
$share->setNodeCacheEntry( |
731
|
|
|
Cache::cacheEntryFromData( |
732
|
|
|
$entryData, |
733
|
|
|
OC::$server->getMimeTypeLoader() |
734
|
|
|
) |
735
|
|
|
); |
736
|
|
|
} |
737
|
|
|
} |
738
|
|
|
|
739
|
|
|
|
740
|
|
|
/** |
741
|
|
|
* @param IShare $share |
742
|
|
|
* @param $data |
743
|
|
|
*/ |
744
|
|
|
private function assignShareObjectSharesProperties(IShare &$share, $data) { |
745
|
|
|
$shareTime = new \DateTime(); |
746
|
|
|
$shareTime->setTimestamp((int)$data['stime']); |
747
|
|
|
|
748
|
|
|
$share->setShareTime($shareTime); |
749
|
|
|
$share->setSharedWith($data['share_with']) |
750
|
|
|
->setSharedBy($data['uid_initiator']) |
751
|
|
|
->setShareOwner($data['uid_owner']) |
752
|
|
|
->setShareType((int)$data['share_type']); |
753
|
|
|
|
754
|
|
|
if (array_key_exists('circle_type', $data) |
755
|
|
|
&& method_exists($share, 'setSharedWithDisplayName')) { |
756
|
|
|
$share->setSharedWithAvatar(CirclesService::getCircleIcon($data['circle_type'])) |
757
|
|
|
->setSharedWithDisplayName( |
758
|
|
|
sprintf( |
759
|
|
|
'%s (%s, %s)', $data['circle_name'], |
760
|
|
|
Circle::TypeLongString($data['circle_type']), |
761
|
|
|
$this->miscService->getDisplayName($data['circle_owner']) |
762
|
|
|
) |
763
|
|
|
); |
764
|
|
|
} |
765
|
|
|
} |
766
|
|
|
|
767
|
|
|
|
768
|
|
|
/** |
769
|
|
|
* @param IShare $share |
770
|
|
|
* |
771
|
|
|
* @return Exception |
772
|
|
|
*/ |
773
|
|
|
private function errorShareAlreadyExist($share) { |
774
|
|
|
$share_src = $share->getNode() |
775
|
|
|
->getName(); |
776
|
|
|
|
777
|
|
|
$message = 'Sharing %s failed, this item is already shared with this circle'; |
778
|
|
|
$message_t = $this->l10n->t($message, array($share_src)); |
779
|
|
|
$this->logger->debug( |
780
|
|
|
sprintf($message, $share_src, $share->getSharedWith()), ['app' => 'circles'] |
781
|
|
|
); |
782
|
|
|
|
783
|
|
|
return new Exception($message_t); |
784
|
|
|
} |
785
|
|
|
|
786
|
|
|
|
787
|
|
|
/** |
788
|
|
|
* Get the access list to the array of provided nodes. |
789
|
|
|
* |
790
|
|
|
* @param Node[] $nodes The list of nodes to get access for |
791
|
|
|
* @param bool $currentAccess If current access is required (like for removed shares that might |
792
|
|
|
* get revived later) |
793
|
|
|
* |
794
|
|
|
* @return array |
|
|
|
|
795
|
|
|
* @see IManager::getAccessList() for sample docs |
796
|
|
|
* |
797
|
|
|
* @since 12 |
798
|
|
|
*/ |
799
|
|
|
public function getAccessList($nodes, $currentAccess) { |
800
|
|
|
$ids = []; |
801
|
|
|
foreach ($nodes as $node) { |
802
|
|
|
$ids[] = $node->getId(); |
803
|
|
|
} |
804
|
|
|
|
805
|
|
|
$qb = $this->getAccessListBaseSelectSql(); |
806
|
|
|
$this->limitToFiles($qb, $ids); |
807
|
|
|
|
808
|
|
|
$users = $this->parseAccessListResult($qb); |
809
|
|
|
|
810
|
|
|
if ($currentAccess === false) { |
811
|
|
|
$users = array_keys($users); |
812
|
|
|
} |
813
|
|
|
|
814
|
|
|
return ['users' => $users]; |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
|
818
|
|
|
/** |
819
|
|
|
* Restore a share for a given recipient. The implementation could be provider independant. |
820
|
|
|
* |
821
|
|
|
* @param IShare $share |
822
|
|
|
* @param string $recipient |
823
|
|
|
* |
824
|
|
|
* @return IShare The restored share object |
825
|
|
|
* |
826
|
|
|
* @since 14.0.0 |
827
|
|
|
*/ |
828
|
|
|
public function restore(IShare $share, string $recipient): IShare { |
829
|
|
|
return $share; |
830
|
|
|
} |
831
|
|
|
|
832
|
|
|
|
833
|
|
|
/** |
834
|
|
|
* return array regarding getAccessList format. |
835
|
|
|
* ie. \OC\Share20\Manager::getAccessList() |
836
|
|
|
* |
837
|
|
|
* @param IQueryBuilder $qb |
838
|
|
|
* |
839
|
|
|
* @return array |
840
|
|
|
*/ |
841
|
|
|
private function parseAccessListResult(IQueryBuilder $qb) { |
842
|
|
|
|
843
|
|
|
$cursor = $qb->execute(); |
844
|
|
|
$users = []; |
845
|
|
|
|
846
|
|
|
while ($row = $cursor->fetch()) { |
847
|
|
|
$userId = $row['user_id']; |
848
|
|
|
|
849
|
|
|
if (!key_exists($userId, $users)) { |
850
|
|
|
$users[$userId] = [ |
851
|
|
|
'node_id' => $row['file_source'], |
852
|
|
|
'node_path' => $row['file_target'] |
853
|
|
|
]; |
854
|
|
|
} |
855
|
|
|
} |
856
|
|
|
$cursor->closeCursor(); |
857
|
|
|
|
858
|
|
|
return $users; |
859
|
|
|
} |
860
|
|
|
|
861
|
|
|
|
862
|
|
|
/** |
863
|
|
|
* @param IShare $share |
864
|
|
|
* |
865
|
|
|
* @return array |
866
|
|
|
* @throws NotFoundException |
867
|
|
|
*/ |
868
|
|
|
private function shareObjectToArray(IShare $share) { |
869
|
|
|
return [ |
870
|
|
|
'id' => $share->getId(), |
871
|
|
|
'sharedWith' => $share->getSharedWith(), |
872
|
|
|
'sharedBy' => $share->getSharedBy(), |
873
|
|
|
'nodeId' => $share->getNodeId(), |
874
|
|
|
'shareOwner' => $share->getShareOwner(), |
875
|
|
|
'permissions' => $share->getPermissions(), |
876
|
|
|
'token' => $share->getToken(), |
877
|
|
|
'password' => ($share->getPassword() === null) ? '' : $share->getPassword() |
878
|
|
|
]; |
879
|
|
|
} |
880
|
|
|
|
881
|
|
|
|
882
|
|
|
/** |
883
|
|
|
* @param string $k |
884
|
|
|
* @param array $arr |
885
|
|
|
* @param string $default |
886
|
|
|
* |
887
|
|
|
* @return string |
888
|
|
|
*/ |
889
|
|
|
protected function get($k, array $arr, string $default = ''): string { |
890
|
|
|
if ($arr === null) { |
891
|
|
|
return $default; |
892
|
|
|
} |
893
|
|
|
|
894
|
|
|
if (!array_key_exists($k, $arr)) { |
895
|
|
|
$subs = explode('.', $k, 2); |
896
|
|
|
if (sizeof($subs) > 1) { |
897
|
|
|
if (!array_key_exists($subs[0], $arr)) { |
898
|
|
|
return $default; |
899
|
|
|
} |
900
|
|
|
|
901
|
|
|
$r = $arr[$subs[0]]; |
902
|
|
|
if (!is_array($r)) { |
903
|
|
|
return $default; |
904
|
|
|
} |
905
|
|
|
|
906
|
|
|
return $this->get($subs[1], $r, $default); |
907
|
|
|
} else { |
908
|
|
|
return $default; |
909
|
|
|
} |
910
|
|
|
} |
911
|
|
|
|
912
|
|
|
if ($arr[$k] === null || (!is_string($arr[$k]) && (!is_int($arr[$k])))) { |
913
|
|
|
return $default; |
914
|
|
|
} |
915
|
|
|
|
916
|
|
|
return (string)$arr[$k]; |
917
|
|
|
} |
918
|
|
|
|
919
|
|
|
|
920
|
|
|
/** |
921
|
|
|
* @inheritDoc |
922
|
|
|
*/ |
923
|
|
|
public function getAllShares(): iterable { |
924
|
|
|
$qb = $this->dbConnection->getQueryBuilder(); |
925
|
|
|
|
926
|
|
|
$qb->select('*') |
927
|
|
|
->from('share') |
928
|
|
|
->where( |
929
|
|
|
$qb->expr()->orX( |
930
|
|
|
$qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE)) |
931
|
|
|
) |
932
|
|
|
); |
933
|
|
|
|
934
|
|
|
$cursor = $qb->execute(); |
935
|
|
|
while($data = $cursor->fetch()) { |
936
|
|
|
$share = $this->createShareObject($data); |
937
|
|
|
|
938
|
|
|
yield $share; |
939
|
|
|
} |
940
|
|
|
$cursor->closeCursor(); |
941
|
|
|
} |
942
|
|
|
} |
943
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.