Passed
Push — master ( a4d511...6fbf8f )
by Morris
20:15 queued 11s
created

StatusService::clearStatus()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 9
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 14
rs 9.9666
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 array $userIds
109
	 * @return UserStatus[]
110
	 */
111
	public function findByUserIds(array $userIds):array {
112
		return array_map(function ($status) {
113
			return $this->processStatus($status);
114
		}, $this->mapper->findByUserIds($userIds));
115
	}
116
117
	/**
118
	 * @param string $userId
119
	 * @param string $status
120
	 * @param int|null $statusTimestamp
121
	 * @param bool $isUserDefined
122
	 * @return UserStatus
123
	 * @throws InvalidStatusTypeException
124
	 */
125
	public function setStatus(string $userId,
126
							  string $status,
127
							  ?int $statusTimestamp,
128
							  bool $isUserDefined): UserStatus {
129
		try {
130
			$userStatus = $this->mapper->findByUserId($userId);
131
		} catch (DoesNotExistException $ex) {
132
			$userStatus = new UserStatus();
133
			$userStatus->setUserId($userId);
134
		}
135
136
		// Check if status-type is valid
137
		if (!\in_array($status, $this->allowedStatusTypes, true)) {
138
			throw new InvalidStatusTypeException('Status-type "' . $status . '" is not supported');
139
		}
140
		if ($statusTimestamp === null) {
141
			$statusTimestamp = $this->timeFactory->getTime();
142
		}
143
144
		$userStatus->setStatus($status);
145
		$userStatus->setStatusTimestamp($statusTimestamp);
146
		$userStatus->setIsUserDefined($isUserDefined);
147
148
		if ($userStatus->getId() === null) {
0 ignored issues
show
introduced by
The condition $userStatus->getId() === null is always false.
Loading history...
149
			return $this->mapper->insert($userStatus);
150
		}
151
152
		return $this->mapper->update($userStatus);
153
	}
154
155
	/**
156
	 * @param string $userId
157
	 * @param string $messageId
158
	 * @param int|null $clearAt
159
	 * @return UserStatus
160
	 * @throws InvalidMessageIdException
161
	 * @throws InvalidClearAtException
162
	 */
163
	public function setPredefinedMessage(string $userId,
164
										 string $messageId,
165
										 ?int $clearAt): UserStatus {
166
		try {
167
			$userStatus = $this->mapper->findByUserId($userId);
168
		} catch (DoesNotExistException $ex) {
169
			$userStatus = new UserStatus();
170
			$userStatus->setUserId($userId);
171
			$userStatus->setStatus('offline');
172
			$userStatus->setStatusTimestamp(0);
173
			$userStatus->setIsUserDefined(false);
174
		}
175
176
		if (!$this->predefinedStatusService->isValidId($messageId)) {
177
			throw new InvalidMessageIdException('Message-Id "' . $messageId . '" is not supported');
178
		}
179
180
		// Check that clearAt is in the future
181
		if ($clearAt !== null && $clearAt < $this->timeFactory->getTime()) {
182
			throw new InvalidClearAtException('ClearAt is in the past');
183
		}
184
185
		$userStatus->setMessageId($messageId);
186
		$userStatus->setCustomIcon(null);
187
		$userStatus->setCustomMessage(null);
188
		$userStatus->setClearAt($clearAt);
189
190
		if ($userStatus->getId() === null) {
0 ignored issues
show
introduced by
The condition $userStatus->getId() === null is always false.
Loading history...
191
			return $this->mapper->insert($userStatus);
192
		}
193
194
		return $this->mapper->update($userStatus);
195
	}
196
197
	/**
198
	 * @param string $userId
199
	 * @param string|null $statusIcon
200
	 * @param string|null $message
201
	 * @param int|null $clearAt
202
	 * @return UserStatus
203
	 * @throws InvalidClearAtException
204
	 * @throws InvalidStatusIconException
205
	 * @throws StatusMessageTooLongException
206
	 */
207
	public function setCustomMessage(string $userId,
208
									 ?string $statusIcon,
209
									 string $message,
210
									 ?int $clearAt): UserStatus {
211
		try {
212
			$userStatus = $this->mapper->findByUserId($userId);
213
		} catch (DoesNotExistException $ex) {
214
			$userStatus = new UserStatus();
215
			$userStatus->setUserId($userId);
216
			$userStatus->setStatus('offline');
217
			$userStatus->setStatusTimestamp(0);
218
			$userStatus->setIsUserDefined(false);
219
		}
220
221
		// Check if statusIcon contains only one character
222
		if ($statusIcon !== null && !$this->emojiService->isValidEmoji($statusIcon)) {
223
			throw new InvalidStatusIconException('Status-Icon is longer than one character');
224
		}
225
		// Check for maximum length of custom message
226
		if (\mb_strlen($message) > $this->maximumMessageLength) {
227
			throw new StatusMessageTooLongException('Message is longer than supported length of ' . $this->maximumMessageLength . ' characters');
228
		}
229
		// Check that clearAt is in the future
230
		if ($clearAt !== null && $clearAt < $this->timeFactory->getTime()) {
231
			throw new InvalidClearAtException('ClearAt is in the past');
232
		}
233
234
		$userStatus->setMessageId(null);
235
		$userStatus->setCustomIcon($statusIcon);
236
		$userStatus->setCustomMessage($message);
237
		$userStatus->setClearAt($clearAt);
238
239
		if ($userStatus->getId() === null) {
0 ignored issues
show
introduced by
The condition $userStatus->getId() === null is always false.
Loading history...
240
			return $this->mapper->insert($userStatus);
241
		}
242
243
		return $this->mapper->update($userStatus);
244
	}
245
246
	/**
247
	 * @param string $userId
248
	 * @return bool
249
	 */
250
	public function clearStatus(string $userId): bool {
251
		try {
252
			$userStatus = $this->mapper->findByUserId($userId);
253
		} catch (DoesNotExistException $ex) {
254
			// if there is no status to remove, just return
255
			return false;
256
		}
257
258
		$userStatus->setStatus('offline');
259
		$userStatus->setStatusTimestamp(0);
260
		$userStatus->setIsUserDefined(false);
261
262
		$this->mapper->update($userStatus);
263
		return true;
264
	}
265
266
	/**
267
	 * @param string $userId
268
	 * @return bool
269
	 */
270
	public function clearMessage(string $userId): bool {
271
		try {
272
			$userStatus = $this->mapper->findByUserId($userId);
273
		} catch (DoesNotExistException $ex) {
274
			// if there is no status to remove, just return
275
			return false;
276
		}
277
278
		$userStatus->setMessageId(null);
279
		$userStatus->setCustomMessage(null);
280
		$userStatus->setCustomIcon(null);
281
		$userStatus->setClearAt(null);
282
283
		$this->mapper->update($userStatus);
284
		return true;
285
	}
286
287
	/**
288
	 * @param string $userId
289
	 * @return bool
290
	 */
291
	public function removeUserStatus(string $userId): bool {
292
		try {
293
			$userStatus = $this->mapper->findByUserId($userId);
294
		} catch (DoesNotExistException $ex) {
295
			// if there is no status to remove, just return
296
			return false;
297
		}
298
299
		$this->mapper->delete($userStatus);
300
		return true;
301
	}
302
303
	/**
304
	 * Processes a status to check if custom message is still
305
	 * up to date and provides translated default status if needed
306
	 *
307
	 * @param UserStatus $status
308
	 * @returns UserStatus
309
	 */
310
	private function processStatus(UserStatus $status): UserStatus {
311
		$clearAt = $status->getClearAt();
312
		if ($clearAt !== null && $clearAt < $this->timeFactory->getTime()) {
313
			$this->cleanStatus($status);
314
		}
315
		if ($status->getMessageId() !== null) {
0 ignored issues
show
introduced by
The condition $status->getMessageId() !== null is always true.
Loading history...
316
			$this->addDefaultMessage($status);
317
		}
318
319
		return $status;
320
	}
321
322
	/**
323
	 * @param UserStatus $status
324
	 */
325
	private function cleanStatus(UserStatus $status): void {
326
		$status->setMessageId(null);
327
		$status->setCustomIcon(null);
328
		$status->setCustomMessage(null);
329
		$status->setClearAt(null);
330
331
		$this->mapper->update($status);
332
	}
333
334
	/**
335
	 * @param UserStatus $status
336
	 */
337
	private function addDefaultMessage(UserStatus $status): void {
338
		// If the message is predefined, insert the translated message and icon
339
		$predefinedMessage = $this->predefinedStatusService->getDefaultStatusById($status->getMessageId());
340
		if ($predefinedMessage !== null) {
341
			$status->setCustomMessage($predefinedMessage['message']);
342
			$status->setCustomIcon($predefinedMessage['icon']);
343
		}
344
	}
345
}
346