PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.9
Booking for Appointments and Events Calendar – Amelia v2.4.9
2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / src / Application / Commands / Command.php
ameliabooking / src / Application / Commands Last commit date
Bookable 1 month ago Booking 5 days ago Calendar 3 weeks ago Entities 3 weeks ago Google 5 months ago Import 1 week ago Mobile 2 months ago Notification 2 months ago Payment 5 days ago QrCode 3 weeks ago Settings 1 week ago Square 1 week ago Stash 3 weeks ago Stats 8 months ago Test 8 months ago User 5 days ago WhatsNew 5 months ago Command.php 5 days ago CommandHandler.php 1 week ago CommandResult.php 6 months ago SortParamsTrait.php 5 months ago
Command.php
417 lines
1 <?php
2
3 namespace AmeliaBooking\Application\Commands;
4
5 use AmeliaBooking\Application\Common\Exceptions\AccessDeniedException;
6 use AmeliaBooking\Application\Commands\Booking\Appointment\AddBookingCommand;
7 use AmeliaBooking\Application\Commands\Booking\Appointment\DeleteBookingRemotelyCommand;
8 use AmeliaBooking\Application\Commands\Booking\Appointment\SuccessfulBookingCommand;
9 use AmeliaBooking\Application\Commands\Notification\SendUndeliveredNotificationsCommand;
10 use AmeliaBooking\Application\Commands\Notification\UpdateSMSNotificationHistoryCommand;
11 use AmeliaBooking\Application\Commands\Outlook\FetchAccessTokenWithAuthCodeOutlookCommand;
12 use AmeliaBooking\Application\Commands\Payment\CalculatePaymentAmountCommand;
13 use AmeliaBooking\Application\Commands\PaymentGateway\RazorpayPaymentNotifyCommand;
14 use AmeliaBooking\Application\Commands\Square\DisconnectFromSquareAccountCommand;
15 use AmeliaBooking\Application\Commands\Square\SquareRefundWebhookCommand;
16 use AmeliaBooking\Application\Services\User\UserApplicationService;
17 use AmeliaBooking\Domain\Entity\Entities;
18 use AmeliaBooking\Domain\Entity\User\AbstractUser;
19 use AmeliaBooking\Domain\Common\Exceptions\AuthorizationException;
20 use AmeliaBooking\Domain\Services\Permissions\PermissionsService;
21 use AmeliaBooking\Domain\Services\Settings\SettingsService;
22 use AmeliaBooking\Infrastructure\WP\SettingsService\SettingsStorage;
23 use AmeliaVendor\Psr\Http\Message\ServerRequestInterface as Request;
24
25 /**
26 * Class Command
27 *
28 * @package AmeliaBooking\Application\Commands
29 */
30 abstract class Command
31 {
32 protected $args;
33
34 protected $container;
35
36 private $fields = [];
37
38 public $token;
39
40 private $page;
41
42 private $cabinetType;
43
44 private $permissionService;
45
46 private $userApplicationService;
47
48 /**
49 * Command constructor.
50 *
51 * @param $args
52 */
53 public function __construct($args)
54 {
55 $this->args = $args;
56 if (isset($args['type'])) {
57 $this->setField('type', $args['type']);
58 }
59 }
60
61 /**
62 * @return mixed
63 */
64 public function getArgs()
65 {
66 return $this->args;
67 }
68
69 /**
70 * @param mixed $arg Argument to be fetched
71 *
72 * @return null|mixed
73 */
74 public function getArg($arg)
75 {
76 return isset($this->args[$arg]) ? $this->args[$arg] : null;
77 }
78
79 /**
80 * @param $fieldName
81 * @param $fieldValue
82 */
83 public function setField($fieldName, $fieldValue)
84 {
85 $this->fields[$fieldName] = $fieldValue;
86 }
87
88 /**
89 * @param $fieldName
90 */
91 public function removeField($fieldName)
92 {
93 unset($this->fields[$fieldName]);
94 }
95
96 /**
97 * Return a single field
98 *
99 * @param $fieldName
100 *
101 * @return mixed|null
102 */
103 public function getField($fieldName)
104 {
105 return isset($this->fields[$fieldName]) ? $this->fields[$fieldName] : null;
106 }
107
108 /**
109 * Return all fields
110 *
111 * @return array
112 */
113 public function getFields()
114 {
115 return $this->fields;
116 }
117
118 /**
119 * Set Token
120 *
121 * @param Request $request
122 */
123 public function setToken($request): void
124 {
125 $token = null;
126
127 /** @var SettingsService $settingsService */
128 $settingsService = new SettingsService(new SettingsStorage());
129
130 $authorization = $request->getHeaderLine('Authorization');
131
132 if (
133 $authorization !== '' &&
134 ($values = explode(' ', $authorization)) &&
135 sizeof($values) === 2 &&
136 strcasecmp($values[0], 'Bearer') === 0 &&
137 $settingsService->getSetting('roles', 'enabledHttpAuthorization')
138 ) {
139 $token = $values[1];
140 } else {
141 $cookies = $request->getCookieParams();
142 if (!empty($cookies['ameliaToken'])) {
143 $token = $cookies['ameliaToken'];
144 }
145 }
146
147 $this->token = $token;
148 }
149
150 /**
151 * Return Token
152 *
153 * @return string|null
154 */
155 public function getToken()
156 {
157 return $this->token;
158 }
159
160 /**
161 * Set page
162 *
163 * @param string $page
164 */
165 public function setPage($page)
166 {
167 $this->page = explode('-', $page)[0];
168
169 $this->cabinetType = !empty(explode('-', $page)[1]) ? explode('-', $page)[1] : null;
170 }
171
172 /**
173 * Return page
174 *
175 * @return string|null
176 */
177 public function getPage()
178 {
179 return $this->page;
180 }
181
182 /**
183 * @param $request
184 * @return bool
185 */
186 public function validateNonce($request): bool
187 {
188 if (
189 $request->getMethod() === 'POST' &&
190 !self::getToken() &&
191 !($this instanceof CalculatePaymentAmountCommand) &&
192 !($this instanceof AddBookingCommand) &&
193 !($this instanceof DeleteBookingRemotelyCommand) &&
194 !($this instanceof SuccessfulBookingCommand) &&
195 !($this instanceof RazorpayPaymentNotifyCommand) &&
196 !($this instanceof SquareRefundWebhookCommand) &&
197 !($this instanceof DisconnectFromSquareAccountCommand) &&
198 !($this instanceof FetchAccessTokenWithAuthCodeOutlookCommand) &&
199 !($this instanceof UpdateSMSNotificationHistoryCommand)
200 ) {
201 $queryParams = $request->getQueryParams();
202 $nonce = !empty($queryParams['wpAmeliaNonce'])
203 ? $queryParams['wpAmeliaNonce']
204 : ($queryParams['ameliaNonce'] ?? '');
205
206 return (bool) wp_verify_nonce(
207 $nonce,
208 'ajax-nonce'
209 );
210 }
211
212 return true;
213 }
214
215 /**
216 * Commands listed here are meant to be run from an external cron job, so they are reached with a GET request that
217 * carries neither a nonce nor a logged in user. They are protected with a secret key, generated per site and
218 * stored in the "activation" settings, that has to be passed as a "cronKey" query parameter.
219 *
220 * @param $request
221 * @return boolean
222 */
223 public function validateCron($request)
224 {
225 if (!($this instanceof SendUndeliveredNotificationsCommand)) {
226 return true;
227 }
228
229 $settingsService = new SettingsService(new SettingsStorage());
230
231 $cronKey = $settingsService->getSetting('activation', 'cronKey');
232
233 if (empty($cronKey)) {
234 return false;
235 }
236
237 $queryParams = $request->getQueryParams();
238
239 $givenKey = !empty($queryParams['cronKey']) ? $queryParams['cronKey'] : '';
240
241 return is_string($givenKey) && hash_equals((string)$cronKey, $givenKey);
242 }
243
244 /**
245 * Return cabinet type
246 *
247 * @return string|null
248 */
249 public function getCabinetType()
250 {
251 return $this->cabinetType;
252 }
253
254 /**
255 * @return PermissionsService
256 */
257 public function getPermissionService()
258 {
259 return $this->permissionService;
260 }
261
262 /**
263 * @param PermissionsService $permissionService
264 */
265 public function setPermissionService($permissionService)
266 {
267 $this->permissionService = $permissionService;
268 }
269
270 /**
271 * @return UserApplicationService
272 */
273 public function getUserApplicationService()
274 {
275 return $this->userApplicationService;
276 }
277
278 /**
279 * @param UserApplicationService $userApplicationService
280 */
281 public function setUserApplicationService($userApplicationService)
282 {
283 $this->userApplicationService = $userApplicationService;
284 }
285
286 /**
287 * Authorize user
288 *
289 * @return AbstractUser
290 * @throws AuthorizationException
291 * @throws AccessDeniedException
292 */
293 public function authorize($type = null): AbstractUser
294 {
295 if ($type === AbstractUser::USER_ROLE_PROVIDER || $type === AbstractUser::USER_ROLE_CUSTOMER) {
296 /** @var AbstractUser $user */
297 $user = $this->getUserApplicationService()->authorization(
298 $this->getToken(),
299 $type
300 );
301
302 // If user is admin or manager, return user
303 if (
304 $user && (
305 $user->getType() === AbstractUser::USER_ROLE_ADMIN ||
306 $user->getType() === AbstractUser::USER_ROLE_MANAGER
307 )
308 ) {
309 return $user;
310 }
311
312 // If user is not admin or manager, check if user is of the given type
313 if (!$user || $user->getType() !== $type) {
314 throw new AccessDeniedException('You are not allowed');
315 }
316
317 return $user;
318 }
319
320 return $this->getUserApplicationService()->authorization(
321 $this->getPage() === 'cabinet' ? $this->getToken() : null,
322 $this->getCabinetType()
323 );
324 }
325
326 /**
327 * Authorize provider read permission
328 *
329 * @param int $userId
330 * @param string $entity
331 *
332 * @return AbstractUser
333 *
334 * @throws AuthorizationException
335 * @throws AccessDeniedException
336 */
337 public function authorizeProviderReadPermission(int $userId, string $entity = Entities::EMPLOYEES): AbstractUser
338 {
339 // if logged in user is not WP admin, WP Amelia manager or WP Amelia provider, try to authorize as non WP Amelia provider
340 if (
341 !$this->getPermissionService()->currentUserCanRead($entity) ||
342 !$this->getPermissionService()->currentUserCanReadOthers($entity)
343 ) {
344 /** @var AbstractUser $user */
345 $user = $this->authorize(Entities::PROVIDER);
346
347 // if authorized as non WP Amelia provider, check if user ID is the same as the requested user ID
348 if (
349 $user->getType() === AbstractUser::USER_ROLE_PROVIDER &&
350 $user->getId()->getValue() !== $userId
351 ) {
352 throw new AccessDeniedException('You are not allowed');
353 }
354
355 return $user;
356 }
357
358 return $this->getUserApplicationService()->authorization(null, null);
359 }
360
361 /**
362 * Authorize provider write permission
363 *
364 * @param int $userId
365 * @param string $entity
366 *
367 * @return AbstractUser
368 *
369 * @throws AuthorizationException
370 * @throws AccessDeniedException
371 */
372 public function authorizeProviderWritePermission(int $userId, string $entity = Entities::EMPLOYEES): AbstractUser
373 {
374 // if logged in user is not WP admin, WP Amelia manager or WP Amelia provider, try to authorize as non WP Amelia provider
375 if (
376 !$this->getPermissionService()->currentUserCanWrite($entity) ||
377 !$this->getPermissionService()->currentUserCanWriteOthers($entity)
378 ) {
379 /** @var AbstractUser $user */
380 $user = $this->authorize(Entities::PROVIDER);
381
382 // if authorized as non WP Amelia provider, check if user ID is the same as the requested user ID
383 if (
384 $user->getType() === AbstractUser::USER_ROLE_PROVIDER &&
385 $user->getId()->getValue() !== $userId
386 ) {
387 throw new AccessDeniedException('You are not allowed');
388 }
389
390 return $user;
391 }
392
393 return $this->getUserApplicationService()->authorization(null, null);
394 }
395
396 /**
397 * Authorize appointment status write: require write_status capability, or fall
398 * through to provider cabinet JWT auth (mobile/employee panel path).
399 *
400 * @return AbstractUser
401 *
402 * @throws AuthorizationException
403 * @throws AccessDeniedException
404 */
405 public function authorizeAppointmentStatusWrite(): AbstractUser
406 {
407 if ($this->getPermissionService()->currentUserCanWriteStatus(Entities::APPOINTMENTS)) {
408 return $this->getUserApplicationService()->authorization(
409 $this->getPage() === 'cabinet' ? $this->getToken() : null,
410 $this->getCabinetType()
411 );
412 }
413
414 return $this->authorize(Entities::PROVIDER);
415 }
416 }
417