diff --git a/application/Espo/Controllers/Admin.php b/application/Espo/Controllers/Admin.php index c8fb0362cc..6011a804bb 100644 --- a/application/Espo/Controllers/Admin.php +++ b/application/Espo/Controllers/Admin.php @@ -103,5 +103,9 @@ class Admin extends \Espo\Core\Controllers\Base return $this->getContainer()->get('scheduledJob')->getSetupMessage(); } -} - + public function actionAdminNotifications($params, $data) + { + $adminNotificationManager = new \Espo\Core\Utils\AdminNotificationManager($this->getContainer()); + return $adminNotificationManager->getAll(); + } +} \ No newline at end of file diff --git a/application/Espo/Core/Utils/AdminNotificationManager.php b/application/Espo/Core/Utils/AdminNotificationManager.php new file mode 100644 index 0000000000..73f32d3ba0 --- /dev/null +++ b/application/Espo/Core/Utils/AdminNotificationManager.php @@ -0,0 +1,258 @@ +container = $container; + } + + protected function getContainer() + { + return $this->container; + } + + protected function getEntityManager() + { + return $this->getContainer()->get('entityManager'); + } + + protected function getConfig() + { + return $this->getContainer()->get('config'); + } + + protected function getLanaguage() + { + return $this->getContainer()->get('language'); + } + + public function getAll() + { + $notifications = []; + + //is cron configured + if (!$this->isCronConfigured()) { + $notifications[] = array( + 'id' => 'cronNotConfigured', + 'data' => array( + 'id' => 'cronNotConfigured', + 'message' => $this->getLanaguage()->translate('cronNotConfigured', 'messages', 'Admin'), + ), + ); + } + + //is need upgrade instance + $neededUpgrade = $this->getInstanceNeededUpgrade(); + if (!empty($neededUpgrade)) { + $message = $this->getLanaguage()->translate('upgradeInstance', 'messages', 'Admin'); + $notifications[] = array( + 'id' => 'upgradeInstance', + 'data' => array( + 'id' => 'upgradeInstance', + 'message' => $this->prepareMessage($message, $neededUpgrade), + ), + ); + } + + //are extensions needed upgrade + $neededUpgrade = $this->getExtensionsNeededUpgrade(); + if (!empty($neededUpgrade)) { + foreach ($neededUpgrade as $extensionName => $extensionDetails) { + $message = $this->getLanaguage()->translate('upgradeExtension', 'messages', 'Admin'); + $notifications[] = array( + 'id' => 'upgradeExtension' . Util::toCamelCase($extensionName, ' ', true), + 'data' => array( + 'id' => 'upgradeExtension', + 'message' => $this->prepareMessage($message, $extensionDetails), + ), + ); + } + } + + return $notifications; + } + + protected function isCronConfigured() + { + return $this->getContainer()->get('scheduledJob')->isCronConfigured(); + } + + protected function getInstanceNeededUpgrade() + { + $config = $this->getConfig(); + + $latestVersion = $config->get('latestRelease'); + if (isset($latestVersion)) { + $currentVersion = $config->get('version'); + + if (version_compare($latestVersion, $currentVersion, '>')) { + return array( + 'currentVersion' => $currentVersion, + 'latestVersion' => $latestVersion, + ); + } + } + } + + protected function getExtensionsNeededUpgrade() + { + $config = $this->getConfig(); + + $extensions = []; + + $latestExtensionReleases = $config->get('latestExtensionReleases'); + if (!empty($latestExtensionReleases) && is_array($latestExtensionReleases)) { + foreach ($latestExtensionReleases as $extensionName => $extensionLatestVersion) { + + $currentVersion = $this->getExtensionLatestVersion($extensionName); + if (isset($currentVersion) && version_compare($extensionLatestVersion, $currentVersion, '>')) { + $extensions[$extensionName] = array( + 'currentVersion' => $currentVersion, + 'latestVersion' => $extensionLatestVersion, + 'extensionName' => $extensionName, + ); + } + } + } + + return $extensions; + } + + protected function getExtensionLatestVersion($extensionName) + { + $pdo = $this->getEntityManager()->getPDO(); + + $query = " + SELECT version FROM extension + WHERE name='". $extensionName ."' + AND deleted=0 + AND is_installed = 1 + ORDER BY created_at DESC + "; + $sth = $pdo->prepare($query); + $sth->execute(); + + $row = $sth->fetch(\PDO::FETCH_ASSOC); + if (isset($row['version'])) { + return $row['version']; + } + } + + /** + * Set EspoCRM latest release + * + * @param string $version + */ + public function setRelease($version) + { + $config = $this->getConfig(); + $config->set('latestRelease', $version); + $this->isConfigChanged = true; + } + + /** + * Set latest release of an extension + * + * @param string $extensionName + * @param string $version + */ + public function setExtensionRelease($extensionName, $version) + { + $config = $this->getConfig(); + + $latestExtensionReleases = $config->get('latestExtensionReleases', []); + $latestExtensionReleases[$extensionName] = $version; + $config->set('latestExtensionReleases', $latestExtensionReleases); + $this->isConfigChanged = true; + } + + /** + * Save releases after setRelease() and setExtensionRelease() + * + * @return boolean + */ + public function saveReleases() + { + if ($this->isConfigChanged) { + $this->isConfigChanged = false; + return $this->getConfig()->save(); + } + } + + /** + * Create EspoCRM notification for a user + * + * @param string $message + * @param string $userId + * + * @return void + */ + public function createNotification($message, $userId = '1') + { + $notification = $this->getEntityManager()->getEntity('Notification'); + $notification->set(array( + 'type' => 'message', + 'data' => array( + 'userId' => $this->getUser()->id, + 'userName' => $this->getUser()->get('name') + ), + 'userId' => $user->id, + 'message' => $actionData['messageTemplate'] + )); + $this->getEntityManager()->saveEntity($notification); + } + + /** + * Replance variable with values + * + * @param string $message + * @param array $data + * + * @return string + */ + protected function prepareMessage($message, array $data = array()) + { + foreach ($data as $name => $value) { + $message = str_replace('{'.$name.'}', $value, $message); + } + + return $message; + } +} \ No newline at end of file diff --git a/application/Espo/Core/Utils/ScheduledJob.php b/application/Espo/Core/Utils/ScheduledJob.php index cbff7dfe09..ee7de6da4e 100644 --- a/application/Espo/Core/Utils/ScheduledJob.php +++ b/application/Espo/Core/Utils/ScheduledJob.php @@ -28,6 +28,7 @@ ************************************************************************/ namespace Espo\Core\Utils; + use Espo\Core\Exceptions\NotFound; class ScheduledJob @@ -44,6 +45,13 @@ class ScheduledJob protected $allowedMethod = 'run'; + /** + * Last cron run time to check if crontab is configured properly + * + * @var string + */ + protected $lasCronRunTime = '-24 hours'; + /** * @var array - path to cron job files */ @@ -193,4 +201,32 @@ class ScheduledJob ); } + /** + * Check if crontab is configured properly + * + * @return boolean + */ + public function isCronConfigured() + { + $date = new \DateTime($this->lasCronRunTime, new \DateTimeZone("UTC")); + + $query = " + SELECT COUNT(id) as count FROM job + WHERE + deleted = 0 + AND `status` IN ('Success', 'Failed') + AND execute_time > '" . $date->format('Y-m-d H:i:s') . "' + "; + + $pdo = $this->getEntityManager()->getPDO(); + $sth = $pdo->prepare($query); + $sth->execute(); + + $row = $sth->fetch(\PDO::FETCH_ASSOC); + if (isset($row['count']) && $row['count'] >= 1) { + return true; + } + + return false; + } } diff --git a/application/Espo/Resources/i18n/en_US/Admin.json b/application/Espo/Resources/i18n/en_US/Admin.json index 1907a4e8fc..49428fcc21 100644 --- a/application/Espo/Resources/i18n/en_US/Admin.json +++ b/application/Espo/Resources/i18n/en_US/Admin.json @@ -166,7 +166,9 @@ "selectExtensionPackage": "Select extension package", "extensionInstalled": "Extension {name} {version} has been installed.", "installExtension": "Extension {name} {version} is ready for an installation.", - "uninstallConfirmation": "Are you sure you want to uninstall the extension?" + "cronNotConfigured": "Scheduled Jobs are not working. Follow this instruction to configure them.", + "upgradeInstance": "New release {latestVersion} of EspoCRM is available. Follow these steps to upgrade your instance.", + "upgradeExtension": "New release {latestVersion} of {extensionName} is available. Ream more about upgrading extensions." }, "descriptions": { "settings": "System settings of application.", diff --git a/client/res/templates/admin/index.tpl b/client/res/templates/admin/index.tpl index 6c536cf8ca..c0d1d306cb 100644 --- a/client/res/templates/admin/index.tpl +++ b/client/res/templates/admin/index.tpl @@ -18,6 +18,8 @@ {{/each}}
+ {{{this.data.message}}} +
+