Non puoi selezionare più di 25 argomenti
Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
424 righe
19 KiB
424 righe
19 KiB
<?php |
|
declare(strict_types=1); |
|
|
|
/** |
|
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
|
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
|
* |
|
* Licensed under The MIT License |
|
* For full copyright and license information, please see the LICENSE.txt |
|
* Redistributions of files must retain the above copyright notice. |
|
* |
|
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
|
* @link https://cakephp.org CakePHP(tm) Project |
|
* @since 0.2.9 |
|
* @license https://opensource.org/licenses/mit-license.php MIT License |
|
*/ |
|
namespace App\Controller; |
|
|
|
use Cake\Controller\Controller; |
|
use Cake\Event\EventInterface; |
|
use App\Model\Entity\User; |
|
use App\WGS\NotificationsHandler\NotificationsHandler; |
|
use Cake\Core\Configure; |
|
use Cake\Http\Response; |
|
use Cake\ORM\Query; |
|
use Cake\I18n\DateTime; |
|
use Cake\I18n\I18n; |
|
use Exception; |
|
|
|
/** |
|
* Application Controller |
|
* |
|
* Add your application-wide methods in the class below, your controllers |
|
* will inherit them. |
|
* |
|
* @link https://book.cakephp.org/4/en/controllers.html#the-app-controller |
|
*/ |
|
class AppController extends Controller |
|
{ |
|
public ?User $logged_user = null; |
|
|
|
/** |
|
* Initialization hook method. |
|
* |
|
* Use this method to add common initialization code like loading components. |
|
* |
|
* e.g. `$this->loadComponent('FormProtection');` |
|
* |
|
* @return void |
|
*/ |
|
public function initialize(): void |
|
{ |
|
parent::initialize(); |
|
|
|
$this->loadComponent('Authentication.Authentication'); |
|
$this->loadComponent('Flash'); |
|
|
|
// recuperiamo l'entità dello user (se loggato): |
|
$this->logged_user = $this->Authentication->getIdentity(); |
|
|
|
// settiamo il locale come da preferenze utente (se specificato, altrimenti ci pensa il LocaleSelectorMiddleware): |
|
if (!empty($this->logged_user->language_id)) I18n::setLocale($this->fetchTable('Languages')->get($this->logged_user->language_id)->language_code); |
|
$this->set('locale', I18n::getLocale()); |
|
|
|
/* |
|
* Enable the following component for recommended CakePHP form protection settings. |
|
* see https://book.cakephp.org/4/en/controllers/components/form-protection.html |
|
*/ |
|
//$this->loadComponent('FormProtection'); |
|
} |
|
|
|
public function beforeRender(EventInterface $event) |
|
{ |
|
if ($this->getRequest()->is(['json', 'xml', 'csv'])) { |
|
$this->viewBuilder()->disableAutoLayout(); |
|
} |
|
|
|
$sys_admin_menu_items = null; |
|
$menu_sections = []; |
|
$menu_items = []; |
|
$logged_user_id = null; |
|
$logged_user_description = null; |
|
$logged_user_access_type_description = null; |
|
$logged_user_timezone = null; |
|
$logged_user_organisation_description = null; |
|
$logged_user_photo = Configure::read('App.defaultUserPhoto'); |
|
$user_notifications_count = 0; |
|
$user_notifications = []; |
|
|
|
// bisogna recuperare le capabilities utente (se esiste un utente loggato) |
|
if ($this->logged_user) { |
|
// menu SYSADMIN da mostrare solo ai SYSADMIN: |
|
$sys_admin_menu_items = [ |
|
[ |
|
'title' => __('SYSADMIN'), |
|
'icon' => 'lock', |
|
'menu_items' => [ |
|
[ |
|
'title' => __('Gestione competenze'), |
|
'icon' => 'wrench', |
|
'link' => '/capabilities', |
|
], |
|
[ |
|
'title' => __('Test notifiche'), |
|
'icon' => 'bell', |
|
'link' => '/notifications/testAll', |
|
'confirm' => __('Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?'), |
|
'method' => 'POST', |
|
], |
|
], |
|
|
|
], |
|
]; |
|
if (!$this->logged_user->sys_admin) $sys_admin_menu_items = null; |
|
|
|
$logged_user_id = $this->logged_user->id; |
|
$logged_user_description = $this->logged_user->name . ' ' . $this->logged_user->surname; |
|
$logged_user_access_type_description = $this->logged_user->sys_admin ? 'sys_admin' : ($this->logged_user->passepartout ? 'passepartout' : ''); |
|
$logged_user_timezone = $this->logged_user->timezone ?? Configure::read('App.defaultUserTimezone'); |
|
if (isset($this->logged_user->organisation_id)) { |
|
$logged_user_organisation_description = $this->fetchTable('Organisations')->get($this->logged_user->organisation_id, contain: ['Actors'])->actor->description; |
|
} |
|
if (!empty($this->logged_user->photo)) $logged_user_photo = Configure::read('App.userPhotoSrc') . "/" . $this->logged_user->photo; |
|
|
|
$user_notifications_count = $this->fetchTable('Notifications')->find()->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL'])->count(); |
|
|
|
$user_notifications = $this->fetchTable('Notifications') |
|
->find() |
|
->contain('NotificationTypes') |
|
->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL']) |
|
->order(['Notifications.created' => 'DESC']) |
|
->all() |
|
->reduce(function ($acc, $user_notification) { |
|
$notification_info = json_decode($user_notification->info); |
|
$body = strlen($notification_info->body) > 200 ? substr($notification_info->body, 0, 197) . '...' : $notification_info->body; |
|
$icon = $user_notification->notification_type->icon ?? 'bell'; |
|
$time_ago = (new DateTime($user_notification->created))->timeAgoInWords(); |
|
$acc[] = ['id' => $user_notification->id, 'icon' => $icon, 'title' => $notification_info->title, 'body' => $body, 'time_ago' => $time_ago]; |
|
return $acc; |
|
}, []); |
|
|
|
$user_capabilityIds_query = $this->logged_user->getCapabilityIds(true); |
|
|
|
$menu_sections_subquery = $this->fetchTable('MenuSections') |
|
->find() |
|
->select(['MenuSections.id']) |
|
->innerJoinWith('Capabilities') |
|
->where(['Capabilities.id IN' => $user_capabilityIds_query]) |
|
->distinct(['MenuSections.id']); |
|
|
|
$menu_sections = $this->fetchTable('MenuSections') |
|
->find() |
|
->where(['MenuSections.id IN' => $menu_sections_subquery]) |
|
->order(['MenuSections.id' => 'ASC']) |
|
->toArray(); |
|
|
|
if (count($menu_sections) > 0) { |
|
// questo blocco controlla se nella request è presente il query param 'menu_section' |
|
// se è presente e rappresenta un id di menu_section valido, lo settiamo in sessione utente |
|
if ($this->getRequest()->getQuery('menu_section')) { |
|
$valid_user_menu_section = $this->fetchTable('MenuSections')->find() |
|
->matching('Capabilities') |
|
->where(['Capabilities.id IN' => $user_capabilityIds_query, 'MenuSections.id' => $this->getRequest()->getQuery('menu_section')]) |
|
->first(); |
|
|
|
$valid_user_menu_section_id = $valid_user_menu_section ? $valid_user_menu_section->id : $menu_sections[0]->id; |
|
|
|
$this->getRequest()->getSession()->write('menu_section', $valid_user_menu_section_id); |
|
} |
|
$menu_section_id = $this->getRequest()->getSession()->read('menu_section') ?? $menu_sections[0]->id; |
|
|
|
$menu_items_subquery = $this->fetchTable('MenuItems') |
|
->find() |
|
->select(['MenuItems.id']) |
|
->innerJoinWith('Capabilities') |
|
->where(['Capabilities.id IN' => $user_capabilityIds_query]) |
|
->where(['MenuItems.menu_item_id IS NULL']) |
|
->where(['MenuItems.menu_section_id' => $menu_section_id]) |
|
->distinct(['MenuItems.id']); |
|
|
|
$menu_items = $this->fetchTable('MenuItems') |
|
->find() |
|
->where(['MenuItems.id IN' => $menu_items_subquery]) |
|
->order(['MenuItems.menu_order' => 'ASC']) |
|
->toArray(); |
|
} |
|
|
|
if( $this->request->getPath() !== '/notifications/index' ) |
|
{ |
|
$privacy = $this->fetchTable('Privacy') |
|
->find()->orderBy(['created' => 'DESC']) |
|
->first(); |
|
|
|
if(isset($privacy)) |
|
{ |
|
$hasAcceptedPrivacy = $this->fetchTable('PrivacyUsers')->find()->where([ |
|
'PrivacyUsers.user_id' => $this->logged_user->id, |
|
'PrivacyUsers.privacy_id' => $privacy->id |
|
])->first(); |
|
|
|
if( |
|
!isset($hasAcceptedPrivacy) && |
|
$this->request->getParam('controller') != 'Privacy' && |
|
$this->request->getParam('action') != 'accept_privacy' |
|
) { |
|
return $this->redirect(['controller' => 'Privacy', 'action' => 'accept_privacy']); |
|
} |
|
} |
|
} |
|
} |
|
|
|
$this->set('menu_sections', $menu_sections); |
|
$this->set('menu_items', $menu_items); |
|
$this->set('sys_admin_menu_items', $sys_admin_menu_items); |
|
$this->set('logged_user_id', $logged_user_id); |
|
$this->set('logged_user_description', $logged_user_description); |
|
$this->set('logged_user_access_type_description', $logged_user_access_type_description); |
|
$this->set('logged_user_timezone', $logged_user_timezone); |
|
$this->set('logged_user_organisation_description', $logged_user_organisation_description); |
|
$this->set('logged_user_photo', $logged_user_photo); |
|
$this->set('user_notifications_count', $user_notifications_count); |
|
$this->set('user_notifications', $user_notifications); |
|
} |
|
|
|
/** |
|
* gen_random_code |
|
* |
|
* @param Int $length |
|
* @return String |
|
*/ |
|
protected function gen_random_code(Int $length): String { |
|
$characters = "abcdefghijklmnopqrstuvwxyzABCDERFGHIJKLMNOPQRSTUVWXYZ0123456789"; |
|
$randomString = ""; |
|
|
|
for ($i = 0; $i < $length; $i++) { |
|
$randomString .= $characters[mt_rand(0, strlen($characters)-1)]; |
|
} |
|
return $randomString; |
|
} |
|
|
|
/** |
|
* sendNotifications |
|
* |
|
* @param Int|Null $co_id |
|
* @param String $notification_code |
|
* @param Array $options |
|
* @return void |
|
*/ |
|
protected function sendNotifications(Int|Null $co_id, String $notification_code, Array $options) |
|
{ |
|
NotificationsHandler::dispatch($co_id, $notification_code, $options, null, $this->logged_user->id ?? null); |
|
} |
|
|
|
/** |
|
* applyFilters |
|
* |
|
* @param Query $query |
|
* @return Query |
|
*/ |
|
protected function applyFilters(Query $query): Query |
|
{ |
|
// recuperiamo i parametri per costruire la chiave per memorizzare i filtri in sessione. |
|
// i filtri sono "scoped" per utente e per route. Quindi per ogni utente possiamo memorizzare |
|
// filtri relativi a più liste. |
|
$logged_user_id = $this->logged_user->id; |
|
$controller = $this->request->getParam('controller'); |
|
$action = $this->request->getParam('action'); |
|
$filter_session_key = "filters-$logged_user_id-$controller-$action"; |
|
|
|
// recuperiamo i filtri o dal POST data (significa che sono stati appena applicati) |
|
// o dalla sessione (se ci sono): |
|
$filters = $this->request->is('post') ? $this->request->getData('filters') : $this->request->getSession()->read($filter_session_key); |
|
\Cake\Log\Log::write("debug", 'applyFilters - ' . ($this->request->is('post') ? 'POST received' : 'SESSION retrieved') . ' filters: ' . json_encode($filters)); |
|
|
|
// ripuliamo i filtri eliminando prima i valori non validi per ciascun filtro |
|
// e successivamente eliminiamo direttamente i fitri che non hanno valori validi (rimasti): |
|
$filters = collection($filters ?? []) |
|
->map(function ($filter_values, $filter_id) { |
|
return collection($filter_values) |
|
->filter(function ($filter_value) { |
|
// il controllo con === "0" serve per evitare che il sanitiser elimini |
|
// il valore "0" per filtri di tipo "bool" |
|
return !empty($filter_value) || $filter_value === "0"; |
|
}) |
|
->reduce(function ($filter_values, $filter_value) { |
|
$filter_values[] = $filter_value; |
|
return $filter_values; |
|
}, []); |
|
}) |
|
->filter(function ($filter_values, $filter_id) { |
|
return !empty($filter_values); |
|
}) |
|
->toArray(); |
|
|
|
\Cake\Log\Log::write("debug", 'applyFilters - SANITISED filters: ' . json_encode($filters)); |
|
|
|
// se non si è riusciti a recuperare filtri |
|
// o è stato richesto un reset dei filtri tramite POST |
|
// o non ne sono rimasti a seguito della sanitizzazione, |
|
// cancelliamo comunque la sessione alla chiave $filter_session_key |
|
// ed usciamo senza applicare nulla alla query: |
|
if (empty($filters)) { |
|
\Cake\Log\Log::write("debug", "applyFilters - DELETING DATA SESSION with key '$filter_session_key'"); |
|
$this->request->getSession()->delete($filter_session_key); |
|
\Cake\Log\Log::write("debug", 'applyFilters - NO filters to appply!'); |
|
return $query; |
|
} |
|
|
|
// se abbiamo filtri validi e li abbiamo appena ricevuti (POST), li salviamo in sessione: |
|
if ($this->request->is('post')) { |
|
\Cake\Log\Log::write("debug", "applyFilters - WRITING DATA SESSION with key '$filter_session_key': " . json_encode($filters)); |
|
$this->request->getSession()->write($filter_session_key, $filters); |
|
} |
|
|
|
// array delle possibili associations da gestire nella query con ->leftJoinWith(). |
|
// verrà popolato durante il processo di conversione da filtri a conditions: |
|
$associations = []; |
|
|
|
// array delle conditions creato a partire dai filters ricevuti, da gestire nella query con ->where() |
|
$conditions = collection($filters) |
|
// qui trasformiamo i filtri in conditions in base alla tipologia di filtro ricevuto: |
|
->map(function ($filter_values, $filter_id) use (&$associations) { |
|
// recuperiamo le info sul filtro dalla table 'filters' avendo ricevuto l'id del filtro: |
|
$filter = $this->fetchTable('Filters')->get((Int)explode("filter_id_", $filter_id)[1]); |
|
// creazione della condizione in base al tipo di filtro: |
|
switch ($filter->filter_type) { |
|
case 'class': |
|
case 'bool': |
|
$condition = [$filter->search . ' IN' => $filter_values]; |
|
break; |
|
case 'text': |
|
$condition = collection($filter_values) |
|
->map(function ($filter_value) use ($filter) { |
|
return [$filter->search . ' LIKE' => $filter_value]; |
|
}) |
|
->reduce(function ($conditions, $condition) { |
|
$conditions['OR'][] = $condition; |
|
return $conditions; |
|
}, ['OR' => []]); |
|
break; |
|
case 'date': |
|
$condition = collection($filter_values) |
|
->map(function ($filter_value) use ($filter) { |
|
$date_array = explode(" - ", $filter_value); |
|
$from_date = $date_array[0]; |
|
$to_date = $date_array[1]; |
|
return [$filter->search . ' >=' => $from_date, $filter->search . ' <=' => $to_date]; |
|
}) |
|
->reduce(function ($conditions, $condition) { |
|
$conditions['OR'][] = $condition; |
|
return $conditions; |
|
}, ['OR' => []]); |
|
break; |
|
default: |
|
break; |
|
} |
|
// se il filtro è stato gestito e richiede una association, la inseriamo in apposito array: |
|
if (!empty($condition) && !empty($filter->associations)) $associations[] = $filter->associations; |
|
|
|
// se il filtro non è stato gestito, restituiamo null; altrimenti restituiamo la condition |
|
return $condition ?? null; |
|
}) |
|
// qui eliminiamo eventuali conditions null (generate da filtri non (al momento) gestiti: |
|
->filter(function ($condition) { |
|
return !empty($condition); |
|
}) |
|
// infine restituiamo l'array_values delle conditions ottenute: |
|
->reduce(function ($conditions, $condition) { |
|
$conditions[] = $condition; |
|
return $conditions; |
|
}, []); |
|
|
|
\Cake\Log\Log::write("debug", 'applyFilters - conditions applied: ' . json_encode($conditions)); |
|
|
|
if (count($conditions) > 0) $query = $query->where($conditions); |
|
|
|
\Cake\Log\Log::write("debug", 'applyFilters - associations applied: ' . json_encode($associations)); |
|
|
|
foreach ($associations as $association) { |
|
$query = $query->leftJoinWith($association); |
|
} |
|
|
|
if (count($associations) > 0) { |
|
$main_table = $query->getRepository()->getAlias(); |
|
$query = $query->distinct(["$main_table.id"]); |
|
\Cake\Log\Log::write("debug", 'applyFilters - distinct applied: ' . "$main_table.id"); |
|
} |
|
|
|
return $query; |
|
} |
|
|
|
/** |
|
* Respond with JSON |
|
* |
|
* @param int $statusCode HTTP status code |
|
* @param null|object|array|string|null $responseBody Content of the response |
|
* @param string $contentType Content type of the response, default "application/json" |
|
* @return Response |
|
*/ |
|
public function respond(int $statusCode = 200, null|object|array|string $responseBody = null, string $contentType = "application/json") : Response |
|
{ |
|
$responseBody = is_object($responseBody) || is_array($responseBody) ? $responseBody : ['result' => $responseBody]; |
|
|
|
if ($paging = $this->request->getAttribute('paging')) { |
|
$responseBody['pagination'] = $paging; |
|
} |
|
|
|
try { |
|
$encodedBody = json_encode($responseBody, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); |
|
} catch (Exception $e) { |
|
return $this->getResponse() |
|
->withStatus(500) |
|
->withStringBody(json_encode(['error' => 'Failed to encode JSON response'])) |
|
->withType('application/json'); |
|
} |
|
|
|
$response = $this->getResponse() |
|
->withStatus($statusCode) |
|
->withType($contentType) |
|
->withStringBody($encodedBody); |
|
|
|
return $response; |
|
} |
|
}
|
|
|