diff --git a/ajax.php b/ajax.php index 4256bd97c..1751c9ce9 100644 --- a/ajax.php +++ b/ajax.php @@ -104,16 +104,32 @@ switch (get('op')) { break; - case 'hook': + case 'hook-lock': $hook_id = filter('id'); $hook = Hook::find($hook_id); - $init = filter('init'); - if (!empty($init)) { - $response = $hook->prepare(); - } else { - $response = $hook->execute(); - } + $token = $hook->lock(); + + echo json_encode($token); + + break; + + case 'hook-execute': + $hook_id = filter('id'); + $token = filter('token'); + $hook = Hook::find($hook_id); + + $response = $hook->execute($token); + + echo json_encode($response); + + break; + + case 'hook-response': + $hook_id = filter('id'); + $hook = Hook::find($hook_id); + + $response = $hook->response(); echo json_encode($response); diff --git a/assets/src/js/functions/hooks.js b/assets/src/js/functions/hooks.js index 2755ce922..23fa891b3 100644 --- a/assets/src/js/functions/hooks.js +++ b/assets/src/js/functions/hooks.js @@ -26,32 +26,65 @@ function startHooks() { message: globals.translations.hookExecuting.replace('_NAME_', item.name) }); - executeHook(item, true); + startHook(item, true); }); }, }); } /** - * Esegue l'hook e lo visualizza. - * Considerare l'utilizzo di localStorage per bloccare l'esecuzione locale multipla dell'hook nel caso di problemi. + * Richiama l'hook per l'esecuzione. * * @param hook - * @param element_id */ -function executeHook(hook, init) { +function startHook(hook, init) { $.ajax({ url: globals.rootdir + "/ajax.php", type: "get", data: { - op: "hook", + op: "hook-lock", id: hook.id, - init: init, + }, + success: function (data) { + var token = JSON.parse(data); + + if (init) { + hookCount("#hooks-counter"); + + updateHook(hook); + } + + if (token){ + executeHook(hook, token); + } else { + var timeout = 10; + + setTimeout(function () { + startHook(hook); + }, timeout * 1000); + } + }, + }); +} + +/** + * Richiama l'hook per l'esecuzione. + * + * @param hook + * @param token + */ +function executeHook(hook, token) { + $.ajax({ + url: globals.rootdir + "/ajax.php", + type: "get", + data: { + op: "hook-execute", + id: hook.id, + token: token, }, success: function (data) { var result = JSON.parse(data); - - renderHook(hook, result); + updateHook(hook); var timeout; if (result.execute) { @@ -61,12 +94,29 @@ function executeHook(hook, init) { } setTimeout(function () { - executeHook(hook); + startHook(hook); }, timeout * 1000); + }, + }); +} - if (init) { - hookCount("#hooks-counter"); - } +/** + * Aggiorna le informazioni dell'hook. + * + * @param hook + * @param init + */ +function updateHook(hook) { + $.ajax({ + url: globals.rootdir + "/ajax.php", + type: "get", + data: { + op: "hook-response", + id: hook.id, + }, + success: function (data) { + var result = JSON.parse(data); + renderHook(hook, result); // Rimozione eventuale della rotella di caricamento var counter = $("#hooks-counter").text(); diff --git a/index.php b/index.php index c66434b35..c73fcf1d6 100644 --- a/index.php +++ b/index.php @@ -14,7 +14,7 @@ switch ($op) { if ($dbo->isConnected() && $dbo->isInstalled() && auth()->attempt($username, $password)) { $_SESSION['keep_alive'] = true; - // Rimozione log vecchi + // Rimozione log vecchi //$dbo->query('DELETE FROM `zz_operations` WHERE DATE_ADD(`created_at`, INTERVAL 30*24*60*60 SECOND) <= NOW()'); } else { $status = auth()->getCurrentStatus(); diff --git a/modules/aggiornamenti/src/UpdateHook.php b/modules/aggiornamenti/src/UpdateHook.php index db3ac2362..cad88793a 100644 --- a/modules/aggiornamenti/src/UpdateHook.php +++ b/modules/aggiornamenti/src/UpdateHook.php @@ -18,8 +18,10 @@ class UpdateHook extends CachedManager return $result; } - public function response($update) + public function response() { + $update = self::getCache()['results']; + $module = Modules::get('Aggiornamenti'); $link = ROOTDIR.'/controller.php?id_module='.$module->id; diff --git a/modules/backups/src/BackupHook.php b/modules/backups/src/BackupHook.php index aa97a2562..3cdd7e916 100644 --- a/modules/backups/src/BackupHook.php +++ b/modules/backups/src/BackupHook.php @@ -7,6 +7,16 @@ use Hooks\Manager; class BackupHook extends Manager { + public function isSingleton() + { + return true; + } + + public function needsExecution() + { + return setting('Backup automatico') && !Backup::isDailyComplete(); + } + public function execute() { $result = Backup::daily(); @@ -14,23 +24,15 @@ class BackupHook extends Manager return $result; } - public function response($data) + public function response() { - return [ - 'icon' => 'fa fa-file-o text-info', - 'message' => tr('Backup completato!'), - 'show' => true, - ]; - } - - public function prepare() - { - $result = setting('Backup automatico') && !Backup::isDailyComplete(); + $show = boolval(setting('Backup automatico')); + $message = $show && !Backup::isDailyComplete() ? tr('Backup in corso...') : tr('Backup completato!'); return [ - 'icon' => 'fa fa-file-o text-danger', - 'message' => tr('Backup in corso...'), - 'execute' => $result, + 'icon' => 'fa fa-file-o text-success', + 'message' => $message, + 'show' => $show, ]; } } diff --git a/modules/emails/src/EmailHook.php b/modules/emails/src/EmailHook.php index 3461e4b5b..e4697b188 100644 --- a/modules/emails/src/EmailHook.php +++ b/modules/emails/src/EmailHook.php @@ -7,6 +7,26 @@ use Notifications\EmailNotification; class EmailHook extends Manager { + public function isSingleton() + { + return true; + } + + public function needsExecution() + { + $diff = date('Y-m-d', strtotime('-4 hours')); + $failed = function ($query) use ($diff) { + $query->whereDate('failed_at', '<', $diff) + ->orWhereNull('failed_at'); + }; + + $remaining = Mail::whereNull('sent_at') + ->where($failed) + ->count(); + + return !empty($remaining); + } + public function execute() { $accounts = Account::all(); @@ -36,25 +56,14 @@ class EmailHook extends Manager } } - return count($list); + return $list; } - public function response($data) - { - return $this->prepare(); - } - - public function prepare() + public function response() { $yesterday = date('Y-m-d', strtotime('-1 days')); - $diff = date('Y-m-d', strtotime('-4 hours')); $user = auth()->getUser(); - $failed = function ($query) use ($diff) { - $query->whereDate('failed_at', '<', $diff) - ->orWhereNull('failed_at'); - }; - $current = Mail::whereDate('sent_at', '>', $yesterday) ->where('created_by', $user->id) ->count(); @@ -63,17 +72,12 @@ class EmailHook extends Manager ->where('created_by', $user->id) ->count(); - $remaining = Mail::whereNull('sent_at') - ->where($failed) - ->count(); - - $message = !empty($remaining) ? tr('Invio email in corso...') : tr('Invio email completato!'); + $message = $total != $current ? tr('Invio email in corso...') : tr('Invio email completato!'); $message = empty($total) ? tr('Nessuna email presente...') : $message; return [ 'icon' => 'fa fa-envelope text-info', 'message' => $message, - 'execute' => !empty($remaining), 'show' => true, 'progress' => [ 'current' => $current, diff --git a/plugins/importFE/src/InvoiceHook.php b/plugins/importFE/src/InvoiceHook.php index a433eb810..8fb1f4366 100644 --- a/plugins/importFE/src/InvoiceHook.php +++ b/plugins/importFE/src/InvoiceHook.php @@ -14,8 +14,10 @@ class InvoiceHook extends CachedManager return $list; } - public function response($results) + public function response() { + $results = self::getCache()['results']; + $count = count($results); $notify = false; diff --git a/plugins/receiptFE/src/ReceiptHook.php b/plugins/receiptFE/src/ReceiptHook.php index 96cc89812..fbee6a7a5 100644 --- a/plugins/receiptFE/src/ReceiptHook.php +++ b/plugins/receiptFE/src/ReceiptHook.php @@ -14,8 +14,10 @@ class ReceiptHook extends CachedManager return $list; } - public function response($results) + public function response() { + $results = self::getCache()['results']; + $count = count($results); $notify = false; diff --git a/src/Hooks/CachedManager.php b/src/Hooks/CachedManager.php index a2b1762c4..fa90bce2e 100644 --- a/src/Hooks/CachedManager.php +++ b/src/Hooks/CachedManager.php @@ -12,13 +12,15 @@ abstract class CachedManager extends Manager abstract public function data(); + public function needsExecution() + { + return !self::isCached(); + } + public function execute() { if (self::isCached()) { $results = self::getCache()['results']; - - // Interpretazione della cache - $results = json_decode($results, true); } else { $results = $this->data(); @@ -35,6 +37,9 @@ abstract class CachedManager extends Manager $cache = database()->selectOne('zz_hook_cache', '*', ['hook_id' => $hook->id], ['id' => 'DESC']); + // Interpretazione della cache + $cache['results'] = json_decode($cache['results'], true); + self::$cache = $cache; } diff --git a/src/Hooks/Manager.php b/src/Hooks/Manager.php index 635cc3451..7aa576ec3 100644 --- a/src/Hooks/Manager.php +++ b/src/Hooks/Manager.php @@ -16,35 +16,41 @@ abstract class Manager /** * Restituisce le informazioni per la visualizzazione dell'hook. * - * @param $results - * * @return array */ - abstract public function response($results); + abstract public function response(); /** - * Restituisce le informazioni per l'inizializzazione dell'hook. + * Restituisce se l'hook è un singletion, cioè deve essere richiamato solo da una istanza di navigazione. * - * @return array|null + * @return bool */ - public function prepare() + public function isSingleton() { - return [ - 'execute' => true, - ]; + return false; } + /** + * Restituisce se l'hook ha bisogno di una esecuzione;. + * + * @return bool + */ + abstract public function needsExecution(); + + /** + * Gestisce la chiamata per l'esecuzione dell'hook. + * + * @return array|mixed + */ public function manage() { - $prepare = $this->prepare(); - if (empty($prepare['execute'])) { + if (!$this->needsExecution()) { return []; } - $data = $this->execute(); - $results = $this->response($data); + $results = $this->execute(); - return $results; + return []; } /** diff --git a/src/Models/Hook.php b/src/Models/Hook.php index e72c3eeff..ac6323d17 100644 --- a/src/Models/Hook.php +++ b/src/Models/Hook.php @@ -2,6 +2,8 @@ namespace Models; +use Carbon\Carbon; +use Carbon\CarbonInterval; use Common\Model; use Hooks\Manager; use Illuminate\Database\Eloquent\Builder; @@ -27,26 +29,103 @@ class Hook extends Model return $this->module ? $this->module->permission : 'rw'; } - public function execute() + /** + * Restituisce le informazioni sull'esecuzione dell'hook. + * + * @return array + */ + public function execute($token) + { + $hook = $this->getClass(); + + if ($hook->isSingleton() && $token != $this->processing_token) { + return; + } + + $result = $hook->manage(); + + if ($hook->isSingleton()) { + $this->unlock($token); + } + + $result['execute'] = $hook->needsExecution(); + + return $result; + } + + /** + * Restituisce le informazioni per l'inizializzazione grafica dell'hook. + * + * @return array + */ + public function response() + { + $hook = $this->getClass(); + + $response = $hook->response(); + + return $response; + } + + /** + * Imposta il lock sull'hook se non già impostato. + * Timeout di 10 minuti. + * + * @return string|null + */ + public function lock() + { + $hook = $this->getClass(); + if (!$hook->isSingleton()) { + return true; + } + + $result = empty($this->processing_at); + + // Forzatura in caso di freeze per più di 10 minuti + $date = new Carbon($this->processing_at); + $interval = CarbonInterval::make('10 minutes'); + $date = $date->add($interval); + + $now = new Carbon(); + $result |= $date->greaterThan($now); + + $token = null; + if ($result) { + $token = random_string(); + + $this->processing_token = $token; + $this->processing_at = date('Y-m-d H:i:s'); + $this->save(); + } + + return $token; + } + + /** + * Rimuove il lock sull'hook. + * + * @return string|null + */ + public function unlock($token) + { + if ($token == $this->processing_token) { + $this->processing_token = null; + $this->processing_at = null; + $this->save(); + } + } + + public function getClass() { $class = $this->class; $hook = new $class(); if (!$hook instanceof Manager) { - return [ - 'show' => false, - ]; + throw new \UnexpectedValueException(); } - return $hook->manage(); - } - - public function prepare() - { - $class = $this->class; - $hook = new $class(); - - return $hook->prepare(); + return $hook; } /* Relazioni Eloquent */ diff --git a/src/Notifications/EmailNotification.php b/src/Notifications/EmailNotification.php index 427391958..f1a45c3fe 100644 --- a/src/Notifications/EmailNotification.php +++ b/src/Notifications/EmailNotification.php @@ -84,6 +84,12 @@ class EmailNotification extends PHPMailer implements NotificationInterface { $this->mail = $mail; + // Registazione della processazione + if (!empty($this->mail)) { + $this->mail->processing_at = date('Y-m-d H:i:s'); + $this->mail->save(); + } + // Destinatari $receivers = $mail->receivers; foreach ($receivers as $receiver) { @@ -91,7 +97,7 @@ class EmailNotification extends PHPMailer implements NotificationInterface } // Allegati - $uploads = $mail->attachments; + $uploads = $mail->uploads; foreach ($uploads as $upload) { $this->addUpload($upload); } @@ -153,7 +159,7 @@ class EmailNotification extends PHPMailer implements NotificationInterface $this->mail->failed_at = date('Y-m-d H:i:s'); } - //$this->mail->save(); + $this->mail->save(); } $this->SmtpClose();