| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2024-11-25 04:18:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * AppendsLocationData.php | 
					
						
							|  |  |  |  * Copyright (c) 2020 james@firefly-iii.org | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is part of Firefly III (https://github.com/firefly-iii). | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU Affero General Public License as | 
					
						
							|  |  |  |  * published by the Free Software Foundation, either version 3 of the | 
					
						
							|  |  |  |  * License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU Affero General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  |  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | declare(strict_types=1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace FireflyIII\Support\Request; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Trait AppendsLocationData | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | trait AppendsLocationData | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-04 07:44:52 +01:00
										 |  |  |     public function addFromromTransactionStore(array $information, array $return): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $return['store_location'] = false; | 
					
						
							|  |  |  |         if (true === $information['store_location']) { | 
					
						
							|  |  |  |             $long = array_key_exists('longitude', $information) ? $information['longitude'] : null; | 
					
						
							|  |  |  |             $lat  = array_key_exists('latitude', $information) ? $information['latitude'] : null; | 
					
						
							|  |  |  |             if (null !== $long && null !== $lat && $this->validLongitude($long) && $this->validLatitude($lat)) { | 
					
						
							|  |  |  |                 $return['store_location'] = true; | 
					
						
							|  |  |  |                 $return['longitude']      = $information['longitude']; | 
					
						
							|  |  |  |                 $return['latitude']       = $information['latitude']; | 
					
						
							|  |  |  |                 $return['zoom_level']     = $information['zoom_level']; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |     private function validLongitude(string $longitude): bool | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |         $number = (float) $longitude; | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $number >= -180 && $number <= 180; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private function validLatitude(string $latitude): bool | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |         $number = (float) $latitude; | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $number >= -90 && $number <= 90; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Abstract method. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param mixed $key | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return bool | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     abstract public function has($key); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Read the submitted Request data and add new or updated Location data to the array. | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     protected function appendLocationData(array $data, ?string $prefix): array | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |         app('log')->debug(sprintf('Now in appendLocationData("%s")', $prefix), $data); | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  |         $data['store_location']  = false; | 
					
						
							|  |  |  |         $data['update_location'] = false; | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |         $data['remove_location'] = false; | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  |         $data['longitude']       = null; | 
					
						
							|  |  |  |         $data['latitude']        = null; | 
					
						
							|  |  |  |         $data['zoom_level']      = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 20:37:54 +01:00
										 |  |  |         $longitudeKey            = $this->getLocationKey($prefix, 'longitude'); | 
					
						
							|  |  |  |         $latitudeKey             = $this->getLocationKey($prefix, 'latitude'); | 
					
						
							|  |  |  |         $zoomLevelKey            = $this->getLocationKey($prefix, 'zoom_level'); | 
					
						
							|  |  |  |         $isValidPOST             = $this->isValidPost($prefix); | 
					
						
							|  |  |  |         $isValidPUT              = $this->isValidPUT($prefix); | 
					
						
							|  |  |  |         $isValidEmptyPUT         = $this->isValidEmptyPUT($prefix); | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // for a POST (store), all fields must be present and not NULL.
 | 
					
						
							|  |  |  |         if ($isValidPOST) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug('Method is POST and all fields present and not NULL.'); | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |             $data['store_location'] = true; | 
					
						
							| 
									
										
										
										
											2022-05-02 19:35:35 +02:00
										 |  |  |             $data['longitude']      = $this->convertString($longitudeKey); | 
					
						
							|  |  |  |             $data['latitude']       = $this->convertString($latitudeKey); | 
					
						
							|  |  |  |             $data['zoom_level']     = $this->convertString($zoomLevelKey); | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  |         // for a PUT (api update) or POST update (UI)
 | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |         if ($isValidPUT) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug('Method is PUT and all fields present and not NULL.'); | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  |             $data['update_location'] = true; | 
					
						
							| 
									
										
										
										
											2022-05-02 19:35:35 +02:00
										 |  |  |             $data['longitude']       = $this->convertString($longitudeKey); | 
					
						
							|  |  |  |             $data['latitude']        = $this->convertString($latitudeKey); | 
					
						
							|  |  |  |             $data['zoom_level']      = $this->convertString($zoomLevelKey); | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |         if ($isValidEmptyPUT) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug('Method is PUT and all fields present and NULL.'); | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |             $data['remove_location'] = true; | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |         app('log')->debug(sprintf('Returning longitude: "%s", latitude: "%s", zoom level: "%s"', $data['longitude'], $data['latitude'], $data['zoom_level'])); | 
					
						
							|  |  |  |         app('log')->debug( | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |             sprintf( | 
					
						
							|  |  |  |                 'Returning actions: store: %s, update: %s, delete: %s', | 
					
						
							|  |  |  |                 var_export($data['store_location'], true), | 
					
						
							|  |  |  |                 var_export($data['update_location'], true), | 
					
						
							|  |  |  |                 var_export($data['remove_location'], true), | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $data; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private function getLocationKey(?string $prefix, string $key): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (null === $prefix) { | 
					
						
							|  |  |  |             return $key; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return sprintf('%s_%s', $prefix, $key); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-05 08:15:17 +01:00
										 |  |  |     private function isValidPost(?string $prefix): bool | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-11-05 08:15:17 +01:00
										 |  |  |         app('log')->debug('Now in isValidPost()'); | 
					
						
							| 
									
										
										
										
											2021-03-15 07:45:46 +01:00
										 |  |  |         $longitudeKey   = $this->getLocationKey($prefix, 'longitude'); | 
					
						
							|  |  |  |         $latitudeKey    = $this->getLocationKey($prefix, 'latitude'); | 
					
						
							|  |  |  |         $zoomLevelKey   = $this->getLocationKey($prefix, 'zoom_level'); | 
					
						
							|  |  |  |         $hasLocationKey = $this->getLocationKey($prefix, 'has_location'); | 
					
						
							|  |  |  |         // fields must not be null:
 | 
					
						
							|  |  |  |         if (null !== $this->get($longitudeKey) && null !== $this->get($latitudeKey) && null !== $this->get($zoomLevelKey)) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug('All fields present'); | 
					
						
							| 
									
										
										
										
											2021-03-15 07:45:46 +01:00
										 |  |  |             // if is POST and route contains API, this is enough:
 | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  |             if ('POST' === $this->method() && $this->routeIs('api.v1.*')) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                 app('log')->debug('Is API location'); | 
					
						
							| 
									
										
										
										
											2021-03-15 07:45:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  |             // if is POST and route does not contain API, must also have "has_location" = true
 | 
					
						
							| 
									
										
										
										
											2023-11-05 09:40:45 +01:00
										 |  |  |             if ('POST' === $this->method() && $this->routeIs('*.store') && !$this->routeIs('api.v1.*') && '' !== $hasLocationKey) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                 app('log')->debug('Is POST + store route.'); | 
					
						
							| 
									
										
										
										
											2021-03-15 07:45:46 +01:00
										 |  |  |                 $hasLocation = $this->boolean($hasLocationKey); | 
					
						
							|  |  |  |                 if (true === $hasLocation) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                     app('log')->debug('Has form form location'); | 
					
						
							| 
									
										
										
										
											2021-03-15 07:45:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     return true; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                 app('log')->debug('Does not have form location'); | 
					
						
							| 
									
										
										
										
											2021-03-15 07:45:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug('Is not POST API or POST form'); | 
					
						
							| 
									
										
										
										
											2021-03-15 07:45:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |         app('log')->debug('Fields not present'); | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-15 07:45:46 +01:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Abstract method. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return string | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     abstract public function method(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Abstract method. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param mixed ...$patterns | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     abstract public function routeIs(...$patterns); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Abstract method stolen from "InteractsWithInput". | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param null $key | 
					
						
							|  |  |  |      * @param bool $default | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:53:10 +01:00
										 |  |  |      * @SuppressWarnings("PHPMD.BooleanArgumentFlag") | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |      */ | 
					
						
							|  |  |  |     abstract public function boolean($key = null, $default = false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |     private function isValidPUT(?string $prefix): bool | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |         $longitudeKey   = $this->getLocationKey($prefix, 'longitude'); | 
					
						
							|  |  |  |         $latitudeKey    = $this->getLocationKey($prefix, 'latitude'); | 
					
						
							|  |  |  |         $zoomLevelKey   = $this->getLocationKey($prefix, 'zoom_level'); | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  |         $hasLocationKey = $this->getLocationKey($prefix, 'has_location'); | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |         app('log')->debug('Now in isValidPUT()'); | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  |         // all fields must be set:
 | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |         if (null !== $this->get($longitudeKey) && null !== $this->get($latitudeKey) && null !== $this->get($zoomLevelKey)) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug('All fields present.'); | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  |             // must be PUT and API route:
 | 
					
						
							|  |  |  |             if ('PUT' === $this->method() && $this->routeIs('api.v1.*')) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                 app('log')->debug('Is API location'); | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             // if POST and not API route, must also have "has_location"
 | 
					
						
							|  |  |  |             // if is POST and route does not contain API, must also have "has_location" = true
 | 
					
						
							| 
									
										
										
										
											2023-11-05 09:40:45 +01:00
										 |  |  |             if ('POST' === $this->method() && $this->routeIs('*.update') && !$this->routeIs('api.v1.*') && '' !== $hasLocationKey) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                 app('log')->debug('Is POST + store route.'); | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  |                 $hasLocation = $this->boolean($hasLocationKey); | 
					
						
							|  |  |  |                 if (true === $hasLocation) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                     app('log')->debug('Has form location data + has_location'); | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     return true; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                 app('log')->debug('Does not have form location'); | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug('Is not POST API or POST form'); | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |         app('log')->debug('Fields not present'); | 
					
						
							| 
									
										
										
										
											2021-03-16 06:42:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2021-03-08 18:21:49 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private function isValidEmptyPUT(?string $prefix): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $longitudeKey = $this->getLocationKey($prefix, 'longitude'); | 
					
						
							|  |  |  |         $latitudeKey  = $this->getLocationKey($prefix, 'latitude'); | 
					
						
							|  |  |  |         $zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return ( | 
					
						
							| 
									
										
										
										
											2024-12-22 20:37:54 +01:00
										 |  |  |             null === $this->get($longitudeKey) | 
					
						
							|  |  |  |             && null === $this->get($latitudeKey) | 
					
						
							|  |  |  |             && null === $this->get($zoomLevelKey)) | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |                && ( | 
					
						
							|  |  |  |                    'PUT' === $this->method() | 
					
						
							|  |  |  |                    || ('POST' === $this->method() && $this->routeIs('*.update')) | 
					
						
							|  |  |  |                ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-18 08:25:25 +02:00
										 |  |  | } |