Passed
Push — master ( fce6df...8e01ff )
by Georg
14:04 queued 11s
created

StatusService::setCustomMessage()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 37
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 21
c 1
b 0
f 0
nc 10
nop 4
dl 0
loc 37
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2020, Georg Ehrke
7
 *
8
 * @author Georg Ehrke <[email protected]>
9
 *
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program. If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OCA\UserStatus\Service;
27
28
use OCA\UserStatus\Db\UserStatus;
29
use OCA\UserStatus\Db\UserStatusMapper;
30
use OCA\UserStatus\Exception\InvalidClearAtException;
31
use OCA\UserStatus\Exception\InvalidMessageIdException;
32
use OCA\UserStatus\Exception\InvalidStatusIconException;
33
use OCA\UserStatus\Exception\InvalidStatusTypeException;
34
use OCA\UserStatus\Exception\StatusMessageTooLongException;
35
use OCP\AppFramework\Db\DoesNotExistException;
36
use OCP\AppFramework\Utility\ITimeFactory;
37
38
/**
39
 * Class StatusService
40
 *
41
 * @package OCA\UserStatus\Service
42
 */
43
class StatusService {
44
45
	/** @var UserStatusMapper */
46
	private $mapper;
47
48
	/** @var ITimeFactory */
49
	private $timeFactory;
50
51
	/** @var PredefinedStatusService */
52
	private $predefinedStatusService;
53
54
	/** @var EmojiService */
55
	private $emojiService;
56
57
	/** @var string[] */
58
	private $allowedStatusTypes = [
59
		'online',
60
		'away',
61
		'dnd',
62
		'invisible',
63
		'offline'
64
	];
65
66
	/** @var int */
67
	private $maximumMessageLength = 80;
68
69
	/**
70
	 * StatusService constructor.
71
	 *
72
	 * @param UserStatusMapper $mapper
73
	 * @param ITimeFactory $timeFactory
74
	 * @param PredefinedStatusService $defaultStatusService,
75
	 * @param EmojiService $emojiService
76
	 */
77
	public function __construct(UserStatusMapper $mapper,
78
								ITimeFactory $timeFactory,
79
								PredefinedStatusService $defaultStatusService,
80
								EmojiService $emojiService) {
81
		$this->mapper = $mapper;
82
		$this->timeFactory = $timeFactory;
83
		$this->predefinedStatusService = $defaultStatusService;
84
		$this->emojiService = $emojiService;
85
	}
86
87
	/**
88
	 * @param int|null $limit
89
	 * @param int|null $offset
90
	 * @return UserStatus[]
91
	 */
92
	public function findAll(?int $limit = null, ?int $offset = null): array {
93
		return array_map(function ($status) {
94
			return $this->processStatus($status);
95
		}, $this->mapper->findAll($limit, $offset));
96
	}
97
98
	/**
99
	 * @param string $userId
100
	 * @return UserStatus
101
	 * @throws DoesNotExistException
102
	 */
103
	public function findByUserId(string $userId):UserStatus {
104
		return $this->processStatus($this->mapper->findByUserId($userId));
105
	}
106
107
	/**
108
	 * @param string $userId
109
	 * @param string $status
110
	 * @param int|null $statusTimestamp
111
	 * @param bool $isUserDefined
112
	 * @return UserStatus
113
	 * @throws InvalidStatusTypeException
114
	 */
115
	public function setStatus(string $userId,
116
							  string $status,
117
							  ?int $statusTimestamp,
118
							  bool $isUserDefined): UserStatus {
119
		try {
120
			$userStatus = $this->mapper->findByUserId($userId);
121
		} catch (DoesNotExistException $ex) {
122
			$userStatus = new UserStatus();
123
			$userStatus->setUserId($userId);
124
		}
125
126
		// Check if status-type is valid
127
		if (!\in_array($status, $this->allowedStatusTypes, true)) {
128
			throw new InvalidStatusTypeException('Status-type "' . $status . '" is not supported');
129
		}
130
		if ($statusTimestamp === null) {
131
			$statusTimestamp = $this->timeFactory->getTime();
132
		}
133
134
		$userStatus->setStatus($status);
135
		$userStatus->setStatusTimestamp($statusTimestamp);
136
		$userStatus->setIsUserDefined($isUserDefined);
137
138
		if ($userStatus->getId() === null) {
0 ignored issues
show
introduced by
The condition $userStatus->getId() === null is always false.
Loading history...
139
			return $this->mapper->insert($userStatus);
140
		}
141
142
		return $this->mapper->update($userStatus);
143
	}
144
145
	/**
146
	 * @param string $userId
147
	 * @param string $messageId
148
	 * @param int|null $clearAt
149
	 * @return UserStatus
150
	 * @throws InvalidMessageIdException
151
	 * @throws InvalidClearAtException
152
	 */
153
	public function setPredefinedMessage(string $userId,
154
										 string $messageId,
155
										 ?int $clearAt): UserStatus {
156
		try {
157
			$userStatus = $this->mapper->findByUserId($userId);
158
		} catch (DoesNotExistException $ex) {
159
			$userStatus = new UserStatus();
160
			$userStatus->setUserId($userId);
161
			$userStatus->setStatus('offline');
162
			$userStatus->setStatusTimestamp(0);
163
			$userStatus->setIsUserDefined(false);
164
		}
165
166
		if (!$this->predefinedStatusService->isValidId($messageId)) {
167
			throw new InvalidMessageIdException('Message-Id "' . $messageId . '" is not supported');
168
		}
169
170
		// Check that clearAt is in the future
171
		if ($clearAt !== null && $clearAt < $this->timeFactory->getTime()) {
172
			throw new InvalidClearAtException('ClearAt is in the past');
173
		}
174
175
		$userStatus->setMessageId($messageId);
176
		$userStatus->setCustomIcon(null);
177
		$userStatus->setCustomMessage(null);
178
		$userStatus->setClearAt($clearAt);
179
180
		if ($userStatus->getId() === null) {
0 ignored issues
show
introduced by
The condition $userStatus->getId() === null is always false.
Loading history...
181
			return $this->mapper->insert($userStatus);
182
		}
183
184
		return $this->mapper->update($userStatus);
185
	}
186
187
	/**
188
	 * @param string $userId
189
	 * @param string|null $statusIcon
190
	 * @param string|null $message
191
	 * @param int|null $clearAt
192
	 * @return UserStatus
193
	 * @throws InvalidClearAtException
194
	 * @throws InvalidStatusIconException
195
	 * @throws StatusMessageTooLongException
196
	 */
197
	public function setCustomMessage(string $userId,
198
									 ?string $statusIcon,
199
									 string $message,
200
									 ?int $clearAt): UserStatus {
201
		try {
202
			$userStatus = $this->mapper->findByUserId($userId);
203
		} catch (DoesNotExistException $ex) {
204
			$userStatus = new UserStatus();
205
			$userStatus->setUserId($userId);
206
			$userStatus->setStatus('offline');
207
			$userStatus->setStatusTimestamp(0);
208
			$userStatus->setIsUserDefined(false);
209
		}
210
211
		// Check if statusIcon contains only one character
212
		if ($statusIcon !== null && !$this->emojiService->isValidEmoji($statusIcon)) {
213
			throw new InvalidStatusIconException('Status-Icon is longer than one character');
214
		}
215
		// Check for maximum length of custom message
216
		if (\mb_strlen($message) > $this->maximumMessageLength) {
217
			throw new StatusMessageTooLongException('Message is longer than supported length of ' . $this->maximumMessageLength . ' characters');
218
		}
219
		// Check that clearAt is in the future
220
		if ($clearAt !== null && $clearAt < $this->timeFactory->getTime()) {
221
			throw new InvalidClearAtException('ClearAt is in the past');
222
		}
223
224
		$userStatus->setMessageId(null);
225
		$userStatus->setCustomIcon($statusIcon);
226
		$userStatus->setCustomMessage($message);
227
		$userStatus->setClearAt($clearAt);
228
229
		if ($userStatus->getId() === null) {
0 ignored issues
show
introduced by
The condition $userStatus->getId() === null is always false.
Loading history...
230
			return $this->mapper->insert($userStatus);
231
		}
232
233
		return $this->mapper->update($userStatus);
234
	}
235
236
	/**
237
	 * @param string $userId
238
	 * @return bool
239
	 */
240
	public function clearStatus(string $userId): bool {
241
		try {
242
			$userStatus = $this->mapper->findByUserId($userId);
243
		} catch (DoesNotExistException $ex) {
244
			// if there is no status to remove, just return
245
			return false;
246
		}
247
248
		$userStatus->setStatus('offline');
249
		$userStatus->setStatusTimestamp(0);
250
		$userStatus->setIsUserDefined(false);
251
252
		$this->mapper->update($userStatus);
253
		return true;
254
	}
255
256
	/**
257
	 * @param string $userId
258
	 * @return bool
259
	 */
260
	public function clearMessage(string $userId): bool {
261
		try {
262
			$userStatus = $this->mapper->findByUserId($userId);
263
		} catch (DoesNotExistException $ex) {
264
			// if there is no status to remove, just return
265
			return false;
266
		}
267
268
		$userStatus->setMessageId(null);
269
		$userStatus->setCustomMessage(null);
270
		$userStatus->setCustomIcon(null);
271
		$userStatus->setClearAt(null);
272
273
		$this->mapper->update($userStatus);
274
		return true;
275
	}
276
277
	/**
278
	 * @param string $userId
279
	 * @return bool
280
	 */
281
	public function removeUserStatus(string $userId): bool {
282
		try {
283
			$userStatus = $this->mapper->findByUserId($userId);
284
		} catch (DoesNotExistException $ex) {
285
			// if there is no status to remove, just return
286
			return false;
287
		}
288
289
		$this->mapper->delete($userStatus);
290
		return true;
291
	}
292
293
	/**
294
	 * Processes a status to check if custom message is still
295
	 * up to date and provides translated default status if needed
296
	 *
297
	 * @param UserStatus $status
298
	 * @returns UserStatus
299
	 */
300
	private function processStatus(UserStatus $status): UserStatus {
301
		$clearAt = $status->getClearAt();
302
		if ($clearAt !== null && $clearAt < $this->timeFactory->getTime()) {
303
			$this->cleanStatus($status);
304
		}
305
		if ($status->getMessageId() !== null) {
0 ignored issues
show
introduced by
The condition $status->getMessageId() !== null is always true.
Loading history...
306
			$this->addDefaultMessage($status);
307
		}
308
309
		return $status;
310
	}
311
312
	/**
313
	 * @param UserStatus $status
314
	 */
315
	private function cleanStatus(UserStatus $status): void {
316
		$status->setMessageId(null);
317
		$status->setCustomIcon(null);
318
		$status->setCustomMessage(null);
319
		$status->setClearAt(null);
320
321
		$this->mapper->update($status);
322
	}
323
324
	/**
325
	 * @param UserStatus $status
326
	 */
327
	private function addDefaultMessage(UserStatus $status): void {
328
		// If the message is predefined, insert the translated message and icon
329
		$predefinedMessage = $this->predefinedStatusService->getDefaultStatusById($status->getMessageId());
330
		if ($predefinedMessage !== null) {
331
			$status->setCustomMessage($predefinedMessage['message']);
332
			$status->setCustomIcon($predefinedMessage['icon']);
333
		}
334
	}
335
}
336