MeetingService   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 18
eloc 60
dl 0
loc 198
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 5 1
A isActive() 0 3 1
A validateUrl() 0 15 4
A getUrl() 0 15 2
A getServices() 0 8 2
A getDataFromUrl() 0 6 1
A getRoomFromUrl() 0 4 1
A getDefaultService() 0 3 2
A getService() 0 6 2
A generateRoomName() 0 15 1
A getToken() 0 8 1
1
<?php
2
3
/**
4
 * Meeting Service.
5
 *
6
 * @package App
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
10
 * @author    Radosław Skrzypczak <[email protected]>
11
 */
12
13
namespace App;
14
15
/**
16
 * Class MeetingService.
17
 */
18
class MeetingService extends Base
19
{
20
	/**
21
	 * Table name.
22
	 */
23
	public const TABLE_NAME = 's_#__meeting_services';
24
25
	/**
26
	 * @var int Status active
27
	 */
28
	private const STATUS_ACTIVE = 1;
29
30
	/**
31
	 * @var int Default service ID
32
	 */
33
	public const DEFAULT_SERVICE = 0;
34
35
	/**
36
	 * Return object instance.
37
	 *
38
	 * @param int $serviceId
39
	 *
40
	 * @return self
41
	 */
42
	public static function getInstance(int $serviceId = self::DEFAULT_SERVICE): self
43
	{
44
		$instance = new self();
45
		$instance->setData(self::getService($serviceId));
46
		return $instance;
47
	}
48
49
	/**
50
	 * Checks if service is active.
51
	 *
52
	 * @return bool
53
	 */
54
	public function isActive(): bool
55
	{
56
		return self::STATUS_ACTIVE === $this->get('status');
57
	}
58
59
	/**
60
	 * Gets services data.
61
	 *
62
	 * @return array
63
	 */
64
	public static function getServices(): array
65
	{
66
		$cacheName = 'MeetingService::getServices';
67
		if (!Cache::has($cacheName, '')) {
68
			$result = (new \App\Db\Query())->from(self::TABLE_NAME)->orderBy(['status' => SORT_DESC])->indexBy('id')->all();
69
			Cache::save($cacheName, '', $result, Cache::LONG);
70
		}
71
		return Cache::get($cacheName, '');
72
	}
73
74
	/**
75
	 * Gets service data.
76
	 *
77
	 * @param int $serviceId
78
	 *
79
	 * @return array
80
	 */
81
	public static function getService(int $serviceId): array
82
	{
83
		if (self::DEFAULT_SERVICE === $serviceId) {
84
			return self::getDefaultService();
85
		}
86
		return self::getServices()[$serviceId] ?? [];
87
	}
88
89
	/**
90
	 * Gets default service data.
91
	 *
92
	 * @return array
93
	 */
94
	public static function getDefaultService(): array
95
	{
96
		return current(self::getServices()) ?: [];
97
	}
98
99
	/**
100
	 * Gets URL address.
101
	 *
102
	 * @param array     $data
103
	 * @param int|null  $userId
104
	 * @param bool|null $moderator
105
	 *
106
	 * @return string
107
	 */
108
	public function getUrl(array $data, ?int $userId = null, ?bool $moderator = false): string
109
	{
110
		if ($userId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $userId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
111
			$userModel = \App\User::getUserModel($userId);
112
			$data['context']['user'] = [
113
				'avatar' => '',
114
				'name' => $userModel->getName(),
115
				'email' => $userModel->getDetail('email1'),
116
				'id' => $userId,
117
			];
118
		}
119
		$data['room'] = $data['room'] ?? $this->generateRoomName();
120
		$data['moderator'] = $moderator;
121
122
		return $this->get('url') . $data['room'] . '?jwt=' . $this->getToken($data);
123
	}
124
125
	/**
126
	 * Generate room name.
127
	 *
128
	 * @param string $prefix
129
	 *
130
	 * @return string
131
	 */
132
	public function generateRoomName(string $prefix = ''): string
133
	{
134
		$prefix = preg_replace_callback_array([
135
			'/[^a-z0-9 ]/' => function () {
136
				return '';
137
			},
138
			'/\b[a-z]/' => function ($matches) {
139
				return mb_strtoupper($matches[0]);
140
			},
141
			'/[\s]/' => function () {
142
				return '';
143
			},
144
		], strtolower(\App\Utils::sanitizeSpecialChars($prefix, ' ')));
145
		[$msec, $sec] = explode(' ', microtime());
146
		return $prefix . 'ID' . str_replace('.', '', $sec . $msec) . random_int(0, 1000);
147
	}
148
149
	/**
150
	 * Gets room name from URL.
151
	 *
152
	 * @param string $url
153
	 *
154
	 * @return string
155
	 */
156
	public function getRoomFromUrl(string $url): string
157
	{
158
		$path = parse_url($url, PHP_URL_PATH);
159
		return \substr($path, 1);
160
	}
161
162
	/**
163
	 * Check URL.
164
	 *
165
	 * @param string $url
166
	 *
167
	 * @return bool
168
	 */
169
	public function validateUrl(string $url): bool
170
	{
171
		$result = false;
172
		$query = parse_url($url, PHP_URL_QUERY);
173
		parse_str($query, $output);
174
		if (!empty($output['jwt']) && 0 === strpos($url, $this->get('url'))) {
175
			try {
176
				$jwt = new \Ahc\Jwt\JWT(\App\Encryption::getInstance()->decrypt($this->get('secret')));
177
				$jwt->decode($output['jwt']);
178
				$result = true;
179
			} catch (\Ahc\Jwt\JWTException $e) {
180
				$result = false;
181
			}
182
		}
183
		return $result;
184
	}
185
186
	/**
187
	 * Gets data from URL.
188
	 *
189
	 * @param string $url
190
	 *
191
	 * @return array
192
	 */
193
	public function getDataFromUrl(string $url): array
194
	{
195
		$query = parse_url($url, PHP_URL_QUERY);
196
		parse_str($query, $output);
197
		$jwt = new \Ahc\Jwt\JWT(\App\Encryption::getInstance()->decrypt($this->get('secret')));
198
		return $jwt->decode($output['jwt']);
199
	}
200
201
	/**
202
	 * Gets token.
203
	 *
204
	 * @param array $data
205
	 *
206
	 * @return void
207
	 */
208
	private function getToken(array $data): string
209
	{
210
		$data['aud'] = $this->get('key');
211
		$data['iss'] = $this->get('key');
212
		$data['sub'] = parse_url($this->get('url'))['host'] ?? '';
213
		$data['exp'] = $data['exp'] ?? strtotime("+{$this->get('duration')} minutes");
214
		$jwt = new \Ahc\Jwt\JWT(\App\Encryption::getInstance()->decrypt($this->get('secret')));
215
		return $jwt->encode($data);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $jwt->encode($data) returns the type string which is incompatible with the documented return type void.
Loading history...
216
	}
217
}
218