Passed
Pull Request — master (#1545)
by Julius
03:01
created

CardMapper::update()   B

Complexity

Conditions 7
Paths 48

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.5066
c 0
b 0
f 0
cc 7
nc 48
nop 2
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 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\Db;
25
26
use OCP\AppFramework\Db\DoesNotExistException;
27
use OCP\AppFramework\Db\Entity;
28
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
29
use OCP\AppFramework\Db\QBMapper;
30
use OCP\DB\QueryBuilder\IQueryBuilder;
31
use OCP\IDBConnection;
32
use OCP\IUserManager;
33
use OCP\Notification\IManager;
34
35
36
class CardMapper extends QBMapper implements IPermissionMapper {
37
38
	/** @var LabelMapper */
39
	private $labelMapper;
40
	/** @var IUserManager */
41
	private $userManager;
42
	/** @var IManager */
43
	private $notificationManager;
44
	private $databaseType;
45
	private $database4ByteSupport;
46
47
	public function __construct(
48
		IDBConnection $db,
49
		LabelMapper $labelMapper,
50
		IUserManager $userManager,
51
		IManager $notificationManager,
52
		$databaseType = 'sqlite',
53
		$database4ByteSupport = true
54
	) {
55
		parent::__construct($db, 'deck_cards', Card::class);
56
		$this->labelMapper = $labelMapper;
57
		$this->userManager = $userManager;
58
		$this->notificationManager = $notificationManager;
59
		$this->databaseType = $databaseType;
60
		$this->database4ByteSupport = $database4ByteSupport;
61
	}
62
63
	public function insert(Entity $entity): Entity {
64
		$entity->setDatabaseType($this->databaseType);
65
		$entity->setCreatedAt(time());
66
		$entity->setLastModified(time());
67
		if (!$this->database4ByteSupport) {
68
			$description = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $entity->getDescription());
69
			$entity->setDescription($description);
70
		}
71
		return parent::insert($entity);
72
	}
73
74
	/**
75
	 * @param IQueryBuilder $query
76
	 * @return Card
77
	 * @throws DoesNotExistException
78
	 * @throws MultipleObjectsReturnedException
79
	 */
80
	public function findEntity(IQueryBuilder $query): Entity {
81
		return parent::findEntity($query);
82
	}
83
84
	public function update(Entity $entity, $updateModified = true): Entity {
85
		if (!$this->database4ByteSupport) {
86
			$description = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $entity->getDescription());
87
			$entity->setDescription($description);
88
		}
89
		$entity->setDatabaseType($this->databaseType);
90
91
		if ($updateModified) {
92
			$entity->setLastModified(time());
93
		}
94
95
		// make sure we only reset the notification flag if the duedate changes
96
		if (in_array('duedate', $entity->getUpdatedFields(), true)) {
97
			/** @var Card $existing */
98
			try {
99
				$existing = $this->find($entity->getId());
100
				if ($existing && $entity->getDuedate() !== $existing->getDuedate()) {
101
					$entity->setNotified(false);
102
				}
103
				// remove pending notifications
104
				$notification = $this->notificationManager->createNotification();
105
				$notification
106
					->setApp('deck')
107
					->setObject('card', $entity->getId());
108
				$this->notificationManager->markProcessed($notification);
109
			} catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
110
			}
111
		}
112
		return parent::update($entity);
113
	}
114
115
	public function markNotified(Card $card) {
116
		$cardUpdate = new Card();
117
		$cardUpdate->setId($card->getId());
118
		$cardUpdate->setNotified(true);
119
		return parent::update($cardUpdate);
120
	}
121
122
	/**
123
	 * @param $id
124
	 * @return RelationalEntity if not found
125
	 * @throws MultipleObjectsReturnedException
126
	 * @throws DoesNotExistException
127
	 */
128
	public function find($id): Card {
129
		$qb = $this->db->getQueryBuilder();
130
		$qb->select('*')
131
			->from('deck_cards')
132
			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
133
		$card = $this->findEntity($qb);
134
		$labels = $this->labelMapper->findAssignedLabelsForCard($card->id);
135
		$card->setLabels($labels);
136
		$this->mapOwner($card);
137
		return $card;
138
	}
139
140
	public function findAll($stackId, $limit = null, $offset = null, $since = -1) {
141
		$qb = $this->db->getQueryBuilder();
142
		$qb->select('*')
143
			->from('deck_cards')
144
			->where($qb->expr()->eq('stack_id', $qb->createNamedParameter($stackId)))
145
			->andWhere($qb->expr()->neq('archived', $qb->createNamedParameter(true)))
146
			->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0)))
147
			->andWhere($qb->expr()->gt('last_modified', $qb->createNamedParameter($since)))
148
			->orderBy('order')
149
			->setMaxResults($limit)
150
			->setFirstResult($offset);
151
		return $this->findEntities($qb);
152
	}
153
154 View Code Duplication
	public function findDeleted($boardId, $limit = null, $offset = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
155
		$qb = $this->db->getQueryBuilder();
156
		$qb->select('*')
157
			->from('deck_cards', 'c')
158
			->join('c', 'deck_stacks', 's', $qb->expr()->eq('s.id', 'c.stack_id'))
159
			->where($qb->expr()->eq('s.board_id', $qb->createNamedParameter($boardId)))
160
			->andWhere($qb->expr()->neq('c.archived', $qb->createNamedParameter(true)))
161
			->andWhere($qb->expr()->neq('c.deleted_at', $qb->createNamedParameter(0)))
162
			->orderBy('c.order')
163
			->setMaxResults($limit)
164
			->setFirstResult($offset);
165
		return $this->findEntities($qb);
166
	}
167
168 View Code Duplication
	public function findCalendarEntries($boardId, $limit = null, $offset = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
169
		$qb = $this->db->getQueryBuilder();
170
		$qb->select('c.*')
171
			->from('deck_cards', 'c')
172
			->join('c', 'deck_stacks', 's', 's.id = c.stack_id')
173
			->where($qb->expr()->eq('s.board_id', $qb->createNamedParameter($boardId)))
174
			->andWhere($qb->expr()->neq('c.archived', $qb->createNamedParameter(true)))
175
			->andWhere($qb->expr()->eq('c.deleted_at', $qb->createNamedParameter('0')))
176
			->andWhere($qb->expr()->isNotNull('c.duedate'))
177
			->orderBy('c.duedate')
178
			->setMaxResults($limit)
179
			->setFirstResult($offset);
180
		return $this->findEntities($qb);
181
	}
182
183
184
	public function findAllArchived($stackId, $limit = null, $offset = null) {
185
		$qb = $this->db->getQueryBuilder();
186
		$qb->select('*')
187
			->from('deck_cards')
188
			->where($qb->expr()->eq('stack_id', $qb->createNamedParameter($stackId)))
189
			->andWhere($qb->expr()->eq('archived', $qb->createNamedParameter(true)))
190
			->orderBy('last_modified')
191
			->setMaxResults($limit)
192
			->setFirstResult($offset);
193
		return $this->findEntities($qb);
194
	}
195
196
	public function findAllByStack($stackId, $limit = null, $offset = null) {
197
		$qb = $this->db->getQueryBuilder();
198
		$qb->select('*')
199
			->from('deck_cards')
200
			->where($qb->expr()->eq('stack_id', $qb->createNamedParameter($stackId)))
201
			->setMaxResults($limit)
202
			->setFirstResult($offset);
203
		return $this->findEntities($qb);
204
	}
205
206
	public function findOverdue() {
207
		$qb = $this->db->getQueryBuilder();
208
		$qb->select('*')
209
			->from('deck_cards')
210
			->where($qb->expr()->lt('duedate', $qb->createFunction('NOW()')))
211
			->andWhere($qb->expr()->neq('archived', $qb->createNamedParameter(true)));
212
		return $this->findEntities($qb);
213
	}
214
215
	public function findUnexposedDescriptionChances() {
216
		$qb = $this->db->getQueryBuilder();
217
		$qb->select('*')
218
			->from('deck_cards')
219
			->where($qb->expr()->isNotNull('last_editor'))
220
			->andWhere($qb->expr()->isNotNull('description_prev'));
221
		return $this->findEntities($qb);
222
	}
223
224
	public function delete(Entity $entity): Entity {
225
		// delete assigned labels
226
		$this->labelMapper->deleteLabelAssignmentsForCard($entity->getId());
227
		// delete card
228
		return parent::delete($entity);
229
	}
230
231
	public function deleteByStack($stackId) {
232
		$cards = $this->findAllByStack($stackId);
233
		foreach ($cards as $card) {
234
			$this->delete($card);
235
		}
236
237
	}
238
239
	public function assignLabel($card, $label) {
240
		$qb = $this->db->getQueryBuilder();
241
		$qb->insert('deck_assigned_labels')
242
			->values([
243
				'label_id' => $qb->createNamedParameter($label, IQueryBuilder::PARAM_INT),
244
				'card_id' => $qb->createNamedParameter($card, IQueryBuilder::PARAM_INT),
245
			]);
246
		$qb->execute();
247
	}
248
249
	public function removeLabel($card, $label) {
250
		$qb = $this->db->getQueryBuilder();
251
		$qb->delete('deck_assigned_labels')
252
			->where($qb->expr()->eq('card_id', $qb->createNamedParameter($card)))
253
			->andWhere($qb->expr()->eq('label_id', $qb->createNamedParameter($label)));
254
		$qb->execute();
255
	}
256
257 View Code Duplication
	public function isOwner($userId, $cardId) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
258
259
		$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_stacks` WHERE id IN (SELECT stack_id FROM `*PREFIX*deck_cards` WHERE id = ?))';
260
		$stmt = $this->db->executeQuery($sql, [$cardId]);
261
		$row = $stmt->fetch();
262
		return ($row['owner'] === $userId);
263
	}
264
265
	public function findBoardId($cardId) {
266
		$sql = 'SELECT id FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_stacks` WHERE id IN (SELECT stack_id FROM `*PREFIX*deck_cards` WHERE id = ?))';
267
		$stmt = $this->db->executeQuery($sql, [$cardId]);
268
		$row = $stmt->fetch();
269
		return $row['id'];
270
	}
271
272 View Code Duplication
	public function mapOwner(Card &$card) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
273
		$userManager = $this->userManager;
274
		$card->resolveRelation('owner', function($owner) use (&$userManager) {
275
			$user = $userManager->get($owner);
276
			if ($user !== null) {
277
				return new User($user);
278
			}
279
			return null;
280
		});
281
	}
282
283
284
}
285