Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2017 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Utils\Util;
|
||||
|
||||
class AdminNotificationManager
|
||||
{
|
||||
private $container;
|
||||
|
||||
private $isConfigChanged = false;
|
||||
|
||||
public function __construct(\Espo\Core\Container $container)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <a target=\"_blank\" href=\"https://www.espocrm.com/documentation/administration/server-configuration/#user-content-setup-a-crontab\">instruction</a> to configure them.",
|
||||
"upgradeInstance": "New release <strong>{latestVersion}</strong> of EspoCRM is available. Follow these steps to upgrade your instance.",
|
||||
"upgradeExtension": "New release <strong>{latestVersion}</strong> of <strong>{extensionName}</strong> is available. Ream more about upgrading extensions."
|
||||
},
|
||||
"descriptions": {
|
||||
"settings": "System settings of application.",
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="admin-notification-panel">{{{adminNotificationPanel}}}</div>
|
||||
|
||||
<iframe src="{{iframeUrl}}" style="width: 100%; height: 874px;" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{{#if notifications}}
|
||||
<div class="panel panel-default panel-default" data-name="default">
|
||||
<div class="panel-body" data-name="default">
|
||||
{{#each notifications}}
|
||||
<div data-id="{{this.id}}">
|
||||
<p class="text-danger">
|
||||
{{{this.data.message}}}
|
||||
</p>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -41,6 +41,11 @@ Espo.define('views/admin/index', 'view', function (Dep) {
|
||||
setup: function () {
|
||||
this.links = this.getMetadata().get('app.adminPanel');
|
||||
this.iframeUrl = this.getConfig().get('adminPanelIframeUrl') || 'https://s.espocrm.com/';
|
||||
|
||||
this.createView('adminNotificationPanel', 'views/admin/panels/admin-notification', {
|
||||
}, function (view) {
|
||||
view.render();
|
||||
}, this);
|
||||
},
|
||||
|
||||
updatePageTitle: function () {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2017 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
Espo.define('views/admin/panels/admin-notification', 'views/base', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'admin/panels/admin-notification',
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
notifications: this.notifications
|
||||
};
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
this.wait(true);
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: 'Admin/action/adminNotifications',
|
||||
error: function (x) {
|
||||
}.bind(this)
|
||||
}).done(function (data) {
|
||||
this.notifications = data;
|
||||
}.bind(this))
|
||||
.always(function (data) {
|
||||
this.wait(false);
|
||||
}.bind(this));
|
||||
|
||||
Dep.prototype.setup.call(this);
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user