Completed
Pull Request — master (#535)
by Julius
02:47
created

AttachmentService::delete()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.1928
c 0
b 0
f 0
cc 5
nc 9
nop 2
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\AppInfo\Application;
28
use OCA\Deck\Db\Acl;
29
use OCA\Deck\Db\Attachment;
30
use OCA\Deck\Db\AttachmentMapper;
31
use OCA\Deck\Db\CardMapper;
32
use OCA\Deck\InvalidAttachmentType;
33
use OCA\Deck\NoPermissionException;
34
use OCA\Deck\NotFoundException;
35
use OCA\Deck\StatusException;
36
use OCP\AppFramework\Http\Response;
37
use OCP\ICache;
38
use OCP\ICacheFactory;
39
use OCP\IL10N;
40
41
class AttachmentService {
42
43
	private $attachmentMapper;
44
	private $cardMapper;
45
	private $permissionService;
46
	private $userId;
47
48
	/** @var IAttachmentService[] */
49
	private $services = [];
50
	private $application;
51
	/** @var ICache */
52
	private $cache;
53
	/** @var IL10N */
54
	private $l10n;
55
56
	/**
57
	 * AttachmentService constructor.
58
	 *
59
	 * @param AttachmentMapper $attachmentMapper
60
	 * @param CardMapper $cardMapper
61
	 * @param PermissionService $permissionService
62
	 * @param Application $application
63
	 * @param ICacheFactory $cacheFactory
64
	 * @param $userId
65
	 * @param IL10N $l10n
66
	 * @throws \OCP\AppFramework\QueryException
67
	 */
68
	public function __construct(AttachmentMapper $attachmentMapper, CardMapper $cardMapper, PermissionService $permissionService, Application $application, ICacheFactory $cacheFactory, $userId, IL10N $l10n) {
69
		$this->attachmentMapper = $attachmentMapper;
70
		$this->cardMapper = $cardMapper;
71
		$this->permissionService = $permissionService;
72
		$this->userId = $userId;
73
		$this->application = $application;
74
		$this->cache = $cacheFactory->createDistributed('deck-card-attachments-');
75
		$this->l10n = $l10n;
76
77
		// Register shipped attachment services
78
		// TODO: move this to a plugin based approach once we have different types of attachments
79
		$this->registerAttachmentService('deck_file', FileService::class);
80
	}
81
82
	/**
83
	 * @param string $type
84
	 * @param string $class
85
	 * @throws \OCP\AppFramework\QueryException
86
	 */
87
	public function registerAttachmentService($type, $class) {
88
		$this->services[$type] = $this->application->getContainer()->query($class);
89
	}
90
91
	/**
92
	 * @param string $type
93
	 * @return IAttachmentService
94
	 * @throws InvalidAttachmentType
95
	 */
96
	public function getService($type) {
97
		if (isset($this->services[$type])) {
98
			return $this->services[$type];
99
		}
100
		throw new InvalidAttachmentType($type);
101
	}
102
103
	/**
104
	 * @param $cardId
105
	 * @return array
106
	 * @throws \OCA\Deck\NoPermissionException
107
	 * @throws BadRequestException
108
	 */
109
	public function findAll($cardId, $withDeleted = false) {
110
111
		if (is_numeric($cardId) === false) {
112
			throw new BadRequestException('card id must be a number');
113
		}
114
115
		$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
116
117
		$attachments = $this->attachmentMapper->findAll($cardId);
118
		if ($withDeleted) {
119
			$attachments = array_merge($attachments, $this->attachmentMapper->findToDelete($cardId, false));
120
		}
121
		foreach ($attachments as &$attachment) {
122
			try {
123
				$service = $this->getService($attachment->getType());
124
				$service->extendData($attachment);
125
			} catch (InvalidAttachmentType $e) {
126
				// Ingore invalid attachment types when extending the data
127
			}
128
		}
129
		return $attachments;
130
	}
131
132
	/**
133
	 * @param $cardId
134
	 * @return int|mixed
135
	 * @throws BadRequestException
136
	 */
137
	public function count($cardId) {
138
139
		if (is_numeric($cardId) === false) {
140
			throw new BadRequestException('card id must be a number');
141
		}
142
143
		$count = $this->cache->get('card-' . $cardId);
144
		if (!$count) {
145
			$count = count($this->attachmentMapper->findAll($cardId));
146
			$this->cache->set('card-' . $cardId, $count);
147
		}
148
		return $count;
149
	}
150
151
	/**
152
	 * @param $cardId
153
	 * @param $type
154
	 * @param $data
155
	 * @return Attachment|\OCP\AppFramework\Db\Entity
156
	 * @throws NoPermissionException
157
	 * @throws StatusException
158
	 * @throws BadRequestException
159
	 */
160
	public function create($cardId, $type, $data) {
161
162
		if (is_numeric($cardId) === false) {
163
			throw new BadRequestException('card id must be a number');
164
		}
165
166
		if ($type === false || $type === null) {
167
			throw new BadRequestException('type must be provided');
168
		}
169
170
		if ($data === false || $data === null) {
171
			throw new BadRequestException('data must be provided');
172
		}
173
174
		$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
175
176
		$this->cache->clear('card-' . $cardId);
177
		$attachment = new Attachment();
178
		$attachment->setCardId($cardId);
179
		$attachment->setType($type);
180
		$attachment->setData($data);
181
		$attachment->setCreatedBy($this->userId);
182
		$attachment->setLastModified(time());
183
		$attachment->setCreatedAt(time());
184
185
		try {
186
			$service = $this->getService($attachment->getType());
187
			$service->create($attachment);
188
		} catch (InvalidAttachmentType $e) {
189
			// just store the data
190
		}
191
		if ($attachment->getData() === null) {
192
			throw new StatusException($this->l10n->t('No data was provided to create an attachment.'));
193
		}
194
		$attachment = $this->attachmentMapper->insert($attachment);
195
196
		// extend data so the frontend can use it properly after creating
197
		try {
198
			$service = $this->getService($attachment->getType());
199
			$service->extendData($attachment);
200
		} catch (InvalidAttachmentType $e) {
201
			// just store the data
202
		}
203
		return $attachment;
204
	}
205
206
207
	/**
208
	 * Display the attachment
209
	 *
210
	 * @param $cardId
211
	 * @param $attachmentId
212
	 * @return Response
213
	 * @throws \OCA\Deck\NotFoundException
214
	 * @throws NoPermissionException
215
	 * @throws NotFoundException
216
	 * @throws \OCP\AppFramework\Db\DoesNotExistException
217
	 * @throws \OCP\AppFramework\Db\
218
	 * @throws BadRequestException
219
	 */
220
	public function display($cardId, $attachmentId) {
221
222
		if (is_numeric($cardId) === false) {
223
			throw new BadRequestException('card id must be a number');
224
		}
225
226
		if (is_numeric($attachmentId) === false) {
227
			throw new BadRequestException('attachment id must be a number');
228
		}
229
230
		$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
231
		$attachment = $this->attachmentMapper->find($attachmentId);
232
233
		try {
234
			$service = $this->getService($attachment->getType());
235
			return $service->display($attachment);
236
		} catch (InvalidAttachmentType $e) {
237
			throw new NotFoundException();
238
		}
239
	}
240
241
	/**
242
	 * Update an attachment with custom data
243
	 *
244
	 * @param $cardId
245
	 * @param $attachmentId
246
	 * @param $request
247
	 * @return mixed
248
	 * @throws \OCA\Deck\NoPermissionException
249
	 * @throws \OCP\AppFramework\Db\DoesNotExistException
250
	 * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
251
	 * @throws BadRequestException
252
	 */
253
	public function update($cardId, $attachmentId, $data) {
254
255
		if (is_numeric($cardId) === false) {
256
			throw new BadRequestException('card id must be a number');
257
		}
258
259
		if (is_numeric($attachmentId) === false) {
260
			throw new BadRequestException('attachment id must be a number');
261
		}
262
263
		if ($data === false || $data === null) {
264
			throw new BadRequestException('data must be provided');
265
		}
266
267
		$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
268
		$this->cache->clear('card-' . $cardId);
269
270
		$attachment = $this->attachmentMapper->find($attachmentId);
271
		$attachment->setData($data);
272
		try {
273
			$service = $this->getService($attachment->getType());
274
			$service->update($attachment);
275
		} catch (InvalidAttachmentType $e) {
276
			// just update without further action
277
		}
278
		$attachment->setLastModified(time());
279
		$this->attachmentMapper->update($attachment);
280
		// extend data so the frontend can use it properly after creating
281
		try {
282
			$service = $this->getService($attachment->getType());
283
			$service->extendData($attachment);
284
		} catch (InvalidAttachmentType $e) {
285
			// just store the data
286
		}
287
		return $attachment;
288
	}
289
290
	/**
291
	 * Either mark an attachment as deleted for later removal or just remove it depending
292
	 * on the IAttachmentService implementation
293
	 *
294
	 * @param $cardId
295
	 * @param $attachmentId
296
	 * @return \OCP\AppFramework\Db\Entity
297
	 * @throws \OCA\Deck\NoPermissionException
298
	 * @throws \OCP\AppFramework\Db\DoesNotExistException
299
	 * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
300
	 * @throws BadRequestException
301
	 */
302
	public function delete($cardId, $attachmentId) {
303
304
		if (is_numeric($cardId) === false) {
305
			throw new BadRequestException('card id must be a number');
306
		}
307
308
		if (is_numeric($attachmentId) === false) {
309
			throw new BadRequestException('attachment id must be a number');
310
		}
311
312
		$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
313
		$this->cache->clear('card-' . $cardId);
314
315
		$attachment = $this->attachmentMapper->find($attachmentId);
316
		try {
317
			$service = $this->getService($attachment->getType());
318
			if ($service->allowUndo()) {
319
				$service->markAsDeleted($attachment);
320
				return $this->attachmentMapper->update($attachment);
321
			}
322
			$service->delete($attachment);
323
		} catch (InvalidAttachmentType $e) {
324
			// just delete without further action
325
		}
326
		return $this->attachmentMapper->delete($attachment);
327
	}
328
329
	public function restore($cardId, $attachmentId) {
330
331
		if (is_numeric($cardId) === false) {
332
			throw new BadRequestException('card id must be a number');
333
		}
334
335
		if (is_numeric($attachmentId) === false) {
336
			throw new BadRequestException('attachment id must be a number');
337
		}
338
339
		$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
340
		$this->cache->clear('card-' . $cardId);
341
342
		$attachment = $this->attachmentMapper->find($attachmentId);
343
		try {
344
			$service = $this->getService($attachment->getType());
345
			if ($service->allowUndo()) {
346
				$attachment->setDeletedAt(0);
347
				return $this->attachmentMapper->update($attachment);
348
			}
349
		} catch (InvalidAttachmentType $e) {
350
		}
351
		throw new NoPermissionException('Restore is not allowed.');
352
	}
353
}