1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @copyright Copyright (c) 2018 Julius Härtl <[email protected]> |
4
|
|
|
* |
5
|
|
|
* @author Julius Härtl <[email protected]> |
6
|
|
|
* |
7
|
|
|
* @license GNU AGPL version 3 or any later version |
8
|
|
|
* |
9
|
|
|
* This program is free software: you can redistribute it and/or modify |
10
|
|
|
* it under the terms of the GNU Affero General Public License as |
11
|
|
|
* published by the Free Software Foundation, either version 3 of the |
12
|
|
|
* License, or (at your option) any later version. |
13
|
|
|
* |
14
|
|
|
* This program is distributed in the hope that it will be useful, |
15
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17
|
|
|
* GNU Affero General Public License for more details. |
18
|
|
|
* |
19
|
|
|
* You should have received a copy of the GNU Affero General Public License |
20
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
21
|
|
|
* |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
namespace OCA\Deck\Service; |
25
|
|
|
|
26
|
|
|
|
27
|
|
|
use OCA\Deck\Activity\ActivityManager; |
28
|
|
|
use OCA\Deck\AppInfo\Application; |
29
|
|
|
use OCA\Deck\BadRequestException; |
30
|
|
|
use OCA\Deck\Db\Acl; |
31
|
|
|
use OCA\Deck\Db\Attachment; |
32
|
|
|
use OCA\Deck\Db\AttachmentMapper; |
33
|
|
|
use OCA\Deck\Db\CardMapper; |
34
|
|
|
use OCA\Deck\Db\ChangeHelper; |
35
|
|
|
use OCA\Deck\InvalidAttachmentType; |
36
|
|
|
use OCA\Deck\NoPermissionException; |
37
|
|
|
use OCA\Deck\NotFoundException; |
38
|
|
|
use OCA\Deck\StatusException; |
39
|
|
|
use OCP\AppFramework\Http\Response; |
40
|
|
|
use OCP\ICache; |
41
|
|
|
use OCP\ICacheFactory; |
42
|
|
|
use OCP\IL10N; |
43
|
|
|
|
44
|
|
|
class AttachmentService { |
45
|
|
|
|
46
|
|
|
private $attachmentMapper; |
47
|
|
|
private $cardMapper; |
48
|
|
|
private $permissionService; |
49
|
|
|
private $userId; |
50
|
|
|
|
51
|
|
|
/** @var IAttachmentService[] */ |
52
|
|
|
private $services = []; |
53
|
|
|
private $application; |
54
|
|
|
/** @var ICache */ |
55
|
|
|
private $cache; |
56
|
|
|
/** @var IL10N */ |
57
|
|
|
private $l10n; |
58
|
|
|
/** @var ActivityManager */ |
59
|
|
|
private $activityManager; |
60
|
|
|
/** @var ChangeHelper */ |
61
|
|
|
private $changeHelper; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* AttachmentService constructor. |
65
|
|
|
* |
66
|
|
|
* @param AttachmentMapper $attachmentMapper |
67
|
|
|
* @param CardMapper $cardMapper |
68
|
|
|
* @param PermissionService $permissionService |
69
|
|
|
* @param Application $application |
70
|
|
|
* @param ICacheFactory $cacheFactory |
71
|
|
|
* @param $userId |
72
|
|
|
* @param IL10N $l10n |
73
|
|
|
* @throws \OCP\AppFramework\QueryException |
74
|
|
|
*/ |
75
|
|
|
public function __construct(AttachmentMapper $attachmentMapper, CardMapper $cardMapper, ChangeHelper $changeHelper, PermissionService $permissionService, Application $application, ICacheFactory $cacheFactory, $userId, IL10N $l10n, ActivityManager $activityManager) { |
76
|
|
|
$this->attachmentMapper = $attachmentMapper; |
77
|
|
|
$this->cardMapper = $cardMapper; |
78
|
|
|
$this->permissionService = $permissionService; |
79
|
|
|
$this->userId = $userId; |
80
|
|
|
$this->application = $application; |
81
|
|
|
$this->cache = $cacheFactory->createDistributed('deck-card-attachments-'); |
82
|
|
|
$this->l10n = $l10n; |
83
|
|
|
$this->activityManager = $activityManager; |
84
|
|
|
$this->changeHelper = $changeHelper; |
85
|
|
|
|
86
|
|
|
// Register shipped attachment services |
87
|
|
|
// TODO: move this to a plugin based approach once we have different types of attachments |
88
|
|
|
$this->registerAttachmentService('deck_file', FileService::class); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* @param string $type |
93
|
|
|
* @param string $class |
94
|
|
|
* @throws \OCP\AppFramework\QueryException |
95
|
|
|
*/ |
96
|
|
|
public function registerAttachmentService($type, $class) { |
97
|
|
|
$this->services[$type] = $this->application->getContainer()->query($class); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @param string $type |
102
|
|
|
* @return IAttachmentService |
103
|
|
|
* @throws InvalidAttachmentType |
104
|
|
|
*/ |
105
|
|
|
public function getService($type) { |
106
|
|
|
if (isset($this->services[$type])) { |
107
|
|
|
return $this->services[$type]; |
108
|
|
|
} |
109
|
|
|
throw new InvalidAttachmentType($type); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @param $cardId |
114
|
|
|
* @return array |
115
|
|
|
* @throws \OCA\Deck\NoPermissionException |
116
|
|
|
* @throws BadRequestException |
117
|
|
|
*/ |
118
|
|
|
public function findAll($cardId, $withDeleted = false) { |
119
|
|
|
|
120
|
|
|
if (is_numeric($cardId) === false) { |
121
|
|
|
throw new BadRequestException('card id must be a number'); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); |
125
|
|
|
|
126
|
|
|
$attachments = $this->attachmentMapper->findAll($cardId); |
127
|
|
|
if ($withDeleted) { |
128
|
|
|
$attachments = array_merge($attachments, $this->attachmentMapper->findToDelete($cardId, false)); |
129
|
|
|
} |
130
|
|
|
foreach ($attachments as &$attachment) { |
131
|
|
|
try { |
132
|
|
|
$service = $this->getService($attachment->getType()); |
133
|
|
|
$service->extendData($attachment); |
134
|
|
|
} catch (InvalidAttachmentType $e) { |
135
|
|
|
// Ingore invalid attachment types when extending the data |
136
|
|
|
} |
137
|
|
|
} |
138
|
|
|
return $attachments; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* @param $cardId |
143
|
|
|
* @return int|mixed |
144
|
|
|
* @throws BadRequestException |
145
|
|
|
*/ |
146
|
|
|
public function count($cardId) { |
147
|
|
|
|
148
|
|
|
if (is_numeric($cardId) === false) { |
149
|
|
|
throw new BadRequestException('card id must be a number'); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
$count = $this->cache->get('card-' . $cardId); |
153
|
|
|
if (!$count) { |
154
|
|
|
$count = count($this->attachmentMapper->findAll($cardId)); |
155
|
|
|
$this->cache->set('card-' . $cardId, $count); |
156
|
|
|
} |
157
|
|
|
return $count; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* @param $cardId |
162
|
|
|
* @param $type |
163
|
|
|
* @param $data |
164
|
|
|
* @return Attachment|\OCP\AppFramework\Db\Entity |
165
|
|
|
* @throws NoPermissionException |
166
|
|
|
* @throws StatusException |
167
|
|
|
* @throws BadRequestException |
168
|
|
|
*/ |
169
|
|
|
public function create($cardId, $type, $data) { |
170
|
|
|
|
171
|
|
|
if (is_numeric($cardId) === false) { |
172
|
|
|
throw new BadRequestException('card id must be a number'); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
if ($type === false || $type === null) { |
176
|
|
|
throw new BadRequestException('type must be provided'); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
if ($data === false || $data === null) { |
|
|
|
|
180
|
|
|
//throw new BadRequestException('data must be provided'); |
|
|
|
|
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); |
184
|
|
|
|
185
|
|
|
$this->cache->clear('card-' . $cardId); |
186
|
|
|
$attachment = new Attachment(); |
187
|
|
|
$attachment->setCardId($cardId); |
188
|
|
|
$attachment->setType($type); |
189
|
|
|
$attachment->setData($data); |
190
|
|
|
$attachment->setCreatedBy($this->userId); |
191
|
|
|
$attachment->setLastModified(time()); |
192
|
|
|
$attachment->setCreatedAt(time()); |
193
|
|
|
|
194
|
|
|
try { |
195
|
|
|
$service = $this->getService($attachment->getType()); |
196
|
|
|
$service->create($attachment); |
197
|
|
|
} catch (InvalidAttachmentType $e) { |
198
|
|
|
// just store the data |
199
|
|
|
} |
200
|
|
|
if ($attachment->getData() === null) { |
201
|
|
|
throw new StatusException($this->l10n->t('No data was provided to create an attachment.')); |
202
|
|
|
} |
203
|
|
|
$attachment = $this->attachmentMapper->insert($attachment); |
|
|
|
|
204
|
|
|
|
205
|
|
|
// extend data so the frontend can use it properly after creating |
206
|
|
|
try { |
207
|
|
|
$service = $this->getService($attachment->getType()); |
208
|
|
|
$service->extendData($attachment); |
209
|
|
|
} catch (InvalidAttachmentType $e) { |
210
|
|
|
// just store the data |
211
|
|
|
} |
212
|
|
|
$this->changeHelper->cardChanged($attachment->getCardId()); |
213
|
|
|
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_CREATE); |
214
|
|
|
return $attachment; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Display the attachment |
220
|
|
|
* |
221
|
|
|
* @param $cardId |
222
|
|
|
* @param $attachmentId |
223
|
|
|
* @return Response |
224
|
|
|
* @throws BadRequestException |
225
|
|
|
* @throws NoPermissionException |
226
|
|
|
* @throws NotFoundException |
227
|
|
|
* @throws \OCP\AppFramework\Db\DoesNotExistException |
228
|
|
|
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException |
229
|
|
|
*/ |
230
|
|
|
public function display($cardId, $attachmentId) { |
231
|
|
|
|
232
|
|
|
if (is_numeric($cardId) === false) { |
233
|
|
|
throw new BadRequestException('card id must be a number'); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
if (is_numeric($attachmentId) === false) { |
237
|
|
|
throw new BadRequestException('attachment id must be a number'); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); |
241
|
|
|
$attachment = $this->attachmentMapper->find($attachmentId); |
242
|
|
|
|
243
|
|
|
try { |
244
|
|
|
$service = $this->getService($attachment->getType()); |
245
|
|
|
return $service->display($attachment); |
246
|
|
|
} catch (InvalidAttachmentType $e) { |
247
|
|
|
throw new NotFoundException(); |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Update an attachment with custom data |
253
|
|
|
* |
254
|
|
|
* @param $cardId |
255
|
|
|
* @param $attachmentId |
256
|
|
|
* @param $request |
257
|
|
|
* @return mixed |
258
|
|
|
* @throws \OCA\Deck\NoPermissionException |
259
|
|
|
* @throws \OCP\AppFramework\Db\DoesNotExistException |
260
|
|
|
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException |
261
|
|
|
* @throws BadRequestException |
262
|
|
|
*/ |
263
|
|
|
public function update($cardId, $attachmentId, $data) { |
264
|
|
|
|
265
|
|
|
if (is_numeric($cardId) === false) { |
266
|
|
|
throw new BadRequestException('card id must be a number'); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
if (is_numeric($attachmentId) === false) { |
270
|
|
|
throw new BadRequestException('attachment id must be a number'); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
if ($data === false || $data === null) { |
|
|
|
|
274
|
|
|
//throw new BadRequestException('data must be provided'); |
|
|
|
|
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); |
278
|
|
|
$this->cache->clear('card-' . $cardId); |
279
|
|
|
|
280
|
|
|
$attachment = $this->attachmentMapper->find($attachmentId); |
281
|
|
|
$attachment->setData($data); |
282
|
|
|
try { |
283
|
|
|
$service = $this->getService($attachment->getType()); |
284
|
|
|
$service->update($attachment); |
285
|
|
|
} catch (InvalidAttachmentType $e) { |
286
|
|
|
// just update without further action |
287
|
|
|
} |
288
|
|
|
$attachment->setLastModified(time()); |
289
|
|
|
$this->attachmentMapper->update($attachment); |
|
|
|
|
290
|
|
|
// extend data so the frontend can use it properly after creating |
291
|
|
|
try { |
292
|
|
|
$service = $this->getService($attachment->getType()); |
293
|
|
|
$service->extendData($attachment); |
294
|
|
|
} catch (InvalidAttachmentType $e) { |
295
|
|
|
// just store the data |
296
|
|
|
} |
297
|
|
|
$this->changeHelper->cardChanged($attachment->getCardId()); |
298
|
|
|
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_UPDATE); |
299
|
|
|
return $attachment; |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* Either mark an attachment as deleted for later removal or just remove it depending |
304
|
|
|
* on the IAttachmentService implementation |
305
|
|
|
* |
306
|
|
|
* @param $cardId |
307
|
|
|
* @param $attachmentId |
308
|
|
|
* @return \OCP\AppFramework\Db\Entity |
309
|
|
|
* @throws \OCA\Deck\NoPermissionException |
310
|
|
|
* @throws \OCP\AppFramework\Db\DoesNotExistException |
311
|
|
|
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException |
312
|
|
|
* @throws BadRequestException |
313
|
|
|
*/ |
314
|
|
|
public function delete($cardId, $attachmentId) { |
315
|
|
|
|
316
|
|
|
if (is_numeric($cardId) === false) { |
317
|
|
|
throw new BadRequestException('card id must be a number'); |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
if (is_numeric($attachmentId) === false) { |
321
|
|
|
throw new BadRequestException('attachment id must be a number'); |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); |
325
|
|
|
$this->cache->clear('card-' . $cardId); |
326
|
|
|
|
327
|
|
|
$attachment = $this->attachmentMapper->find($attachmentId); |
328
|
|
|
try { |
329
|
|
|
$service = $this->getService($attachment->getType()); |
330
|
|
|
if ($service->allowUndo()) { |
331
|
|
|
$service->markAsDeleted($attachment); |
332
|
|
|
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_DELETE); |
333
|
|
|
return $this->attachmentMapper->update($attachment); |
|
|
|
|
334
|
|
|
} |
335
|
|
|
$service->delete($attachment); |
336
|
|
|
} catch (InvalidAttachmentType $e) { |
337
|
|
|
// just delete without further action |
338
|
|
|
} |
339
|
|
|
$attachment = $this->attachmentMapper->delete($attachment); |
|
|
|
|
340
|
|
|
$this->changeHelper->cardChanged($attachment->getCardId()); |
341
|
|
|
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_DELETE); |
342
|
|
|
return $attachment; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
public function restore($cardId, $attachmentId) { |
346
|
|
|
|
347
|
|
|
if (is_numeric($cardId) === false) { |
348
|
|
|
throw new BadRequestException('card id must be a number'); |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
if (is_numeric($attachmentId) === false) { |
352
|
|
|
throw new BadRequestException('attachment id must be a number'); |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); |
356
|
|
|
$this->cache->clear('card-' . $cardId); |
357
|
|
|
|
358
|
|
|
$attachment = $this->attachmentMapper->find($attachmentId); |
359
|
|
|
try { |
360
|
|
|
$service = $this->getService($attachment->getType()); |
361
|
|
|
if ($service->allowUndo()) { |
362
|
|
|
$attachment->setDeletedAt(0); |
363
|
|
|
$attachment = $this->attachmentMapper->update($attachment); |
|
|
|
|
364
|
|
|
$this->changeHelper->cardChanged($attachment->getCardId()); |
365
|
|
|
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_RESTORE); |
366
|
|
|
return $attachment; |
367
|
|
|
} |
368
|
|
|
} catch (InvalidAttachmentType $e) { |
369
|
|
|
} |
370
|
|
|
throw new NoPermissionException('Restore is not allowed.'); |
371
|
|
|
} |
372
|
|
|
} |
373
|
|
|
|
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.