Merge pull request #17309 from atm-john/new/check_update_for_module

NEW : Check update for externals modules using button on module page
This commit is contained in:
Laurent Destailleur 2021-04-19 21:26:14 +02:00 committed by GitHub
commit 35e3c32b14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 113 additions and 24 deletions

View File

@ -520,9 +520,11 @@ if ($mode == 'common' || $mode == 'commonkanban') {
$moreforfilter = '<div class="valignmiddle">';
$moreforfilter .= '<div class="floatright right pagination"><ul><li>';
$moreforfilter .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=commonkanban'.$param, '', 1, array('morecss'=>'reposition'.($mode == 'common' ? '' : ' btnTitleSelected')));
$moreforfilter .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-list-alt imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.$param, '', 1, array('morecss'=>'reposition'.($mode == 'commonkanban' ? '' : ' btnTitleSelected')));
$moreforfilter .= '<div class="floatright right pagination --module-list"><ul><li>';
$moreforfilter .= dolGetButtonTitle($langs->trans('CheckForModuleUpdate'), $langs->trans('CheckForModuleUpdateHelp'), 'fa fa-check-double ', $_SERVER["PHP_SELF"].'?action=checklastversion&token='.newToken().'&mode='.$mode.$param, '', 1, array('morecss'=>'reposition'));
$moreforfilter .= '</li><li>'.dolGetButtonTitleSeparator();
$moreforfilter .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=commonkanban'.$param, '', ($mode == 'commonkanban' ? 2 : 1), array('morecss'=>'reposition'));
$moreforfilter .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-list-alt imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.$param, '', ($mode == 'common' ? 2 : 1), array('morecss'=>'reposition'));
$moreforfilter .= '</li></ul></div>';
//$moreforfilter .= '<div class="floatright center marginrightonly hideonsmartphone" style="padding-top: 3px"><span class="paddingright">'.$moreinfo.'</span> '.$moreinfo2.'</div>';
@ -583,7 +585,6 @@ if ($mode == 'common' || $mode == 'commonkanban') {
// Show list of modules
$oldfamily = '';
$linenum = 0;
foreach ($orders as $key => $value) {
$linenum++;
$tab = explode('_', $value);
@ -591,6 +592,8 @@ if ($mode == 'common' || $mode == 'commonkanban') {
$module_position = $tab[2];
$modName = $filename[$key];
/** @var DolibarrModules $objMod */
$objMod = $modules[$modName];
//print $objMod->name." - ".$key." - ".$objMod->version."<br>";
@ -719,6 +722,22 @@ if ($mode == 'common' || $mode == 'commonkanban') {
$versiontrans .= $objMod->getVersion(1);
}
if ($objMod->isCoreOrExternalModule() == 'external'
&& (
$action == 'checklastversion'
// This is a bad practice to activate a synch external access during building of a page. 1 external module can hang the application.
// Adding a cron job could be a good idea see DolibarrModules::checkForUpdate()
|| !empty($conf->global->CHECKLASTVERSION_EXTERNALMODULE)
)
) {
$checkRes = $objMod->checkForUpdate();
if ($checkRes > 0) {
setEventMessage($objMod->getName().' : '.$versiontrans.' -> '.$objMod->lastVersion);
} elseif ($checkRes < 0) {
setEventMessage($objMod->getName().' '.$langs->trans('CheckVersionFail'), 'warnings');
}
}
// Define imginfo
$imginfo = "info";
if ($objMod->isCoreOrExternalModule() == 'external') {
@ -893,17 +912,11 @@ if ($mode == 'common' || $mode == 'commonkanban') {
// Version
print '<td class="center nowrap" width="120px">';
print $versiontrans;
if (!empty($conf->global->CHECKLASTVERSION_EXTERNALMODULE)) { // This is a bad practice to activate a synch external access during building of a page. 1 external module can hang the application.
require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
if (!empty($objMod->url_last_version)) {
$newversion = getURLContent($objMod->url_last_version, 'GET', '', 1, array(), array('http', 'https'), 0); // Accept http or https links on external remote server only
if (isset($newversion['content'])) {
if (version_compare($newversion['content'], $versiontrans) > 0) {
print "&nbsp;<span class='butAction' title='".$langs->trans('LastStableVersion')."'>".$newversion['content']."</span>";
}
}
}
if ($objMod->needUpdate) {
$versionTitle = $langs->trans('ModuleUpdateAvailable').' : '.$objMod->lastVersion;
print '<span class="badge badge-warning classfortooltip" title="'.dol_escape_htmltag($versionTitle).'">'.$versiontrans.'</span>';
} else {
print $versiontrans;
}
print "</td>\n";

View File

@ -9710,6 +9710,17 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url =
return '<div class="inline-block divButAction"><'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'></div>';
}
/**
* Add space between dolGetButtonTitle
*
* @param string $moreClass more css class label
* @return string html of title separator
*/
function dolGetButtonTitleSeparator($moreClass = "")
{
return '<span class="button-title-separator '.$moreClass.'" ></span>';
}
/**
* Function dolGetButtonTitle : this kind of buttons are used in title in list
*
@ -9718,7 +9729,7 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url =
* @param string $iconClass class for icon element (Example: 'fa fa-file')
* @param string $url the url for link
* @param string $id attribute id of button
* @param int $status 0 no user rights, 1 active, -1 Feature Disabled, -2 disable Other reason use helpText as tooltip
* @param int $status 0 no user rights, 1 active, 2 current action or selected, -1 Feature Disabled, -2 disable Other reason use helpText as tooltip
* @param array $params various params for future : recommended rather than adding more function arguments
* @return string html button
*/
@ -9753,7 +9764,9 @@ function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $u
$useclassfortooltip = 0;
}
if ($status <= 0) {
if ($status == 2) {
$attr['class'] .= ' btnTitleSelected';
} elseif ($status <= 0) {
$attr['class'] .= ' refused';
$attr['href'] = '';

View File

@ -192,6 +192,18 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
*/
public $version;
/**
* Module last version
* @var string $lastVersion
*/
public $lastVersion = '';
/**
* true indicate this module need update
* @var bool $needUpdate
*/
public $needUpdate = false;
/**
* @var string Module description (short text)
*
@ -2240,7 +2252,11 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
}
print '
<div class="box-flex-item info-box-module'.(empty($conf->global->$const_name) ? ' info-box-module-disabled' : '').($this->isCoreOrExternalModule() == 'external' ? ' info-box-module-external' : '').'">
<div class="box-flex-item info-box-module'
.(empty($conf->global->$const_name) ? ' --disabled' : '')
.($this->isCoreOrExternalModule() == 'external' ? ' --external' : '')
.($this->needUpdate ? ' --need-update' : '')
.'">
<div class="info-box info-box-sm info-box-module">
<div class="info-box-icon'.(empty($conf->global->$const_name) ? '' : ' info-box-icon-module-enabled'.($versiontrans ? ' info-box-icon-module-warning' : '')).'">';
@ -2258,7 +2274,12 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
}
if ($this->isCoreOrExternalModule() == 'external' || preg_match('/development|experimental|deprecated/i', $version)) {
print '<span class="info-box-icon-version'.($versiontrans ? ' '.$versiontrans : '').'" title="'.$langs->trans("Version").' '.$this->getVersion(1).'">';
$versionTitle = $langs->trans("Version").' '.$this->getVersion(1);
if ($this->needUpdate) {
$versionTitle.= '<br/>'.$langs->trans('ModuleUpdateAvailable').' : '.$this->lastVersion;
}
print '<span class="info-box-icon-version'.($versiontrans ? ' '.$versiontrans : '').' classfortooltip" title="'.dol_escape_js($versionTitle).'" >';
print $this->getVersion(1);
print '</span>';
}
@ -2287,4 +2308,33 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
</div><!-- /.info-box -->
</div>';
}
/**
* check for module update
* TODO : store results for $this->url_last_version and $this->needUpdate
* Add a cron task to monitor for updates
*
* @return int <0 if Error, 0 == no update needed, >0 if need update
*/
public function checkForUpdate()
{
require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
if (!empty($this->url_last_version)) {
$lastVersion = getURLContent($this->url_last_version, 'GET', '', 1, array(), array('http', 'https'), 0); // Accept http or https links on external remote server only
if (isset($lastVersion['content']) && strlen($lastVersion['content']) < 30) {
// Security warning : be careful with remote data content, the module editor could be hacked (or evil) so limit to a-z A-Z 0-9 _ . -
$this->lastVersion = preg_replace("/[^a-zA-Z0-9_\.\-]+/", "", $lastVersion['content']);
if (version_compare($this->lastVersion, $this->version) > 0) {
$this->needUpdate = true;
return 1;
} else {
$this->needUpdate = false;
return 0;
}
} else {
return -1;
}
}
return 0;
}
}

View File

@ -2122,4 +2122,7 @@ IfCLINotRequiredYouShouldDisablePHPFunctions=Except if you need to run system co
NoWritableFilesFoundIntoRootDir=No writable files or directories of the common programs were found into your root directory (Good)
RecommendedValueIs=Recommended: %s
ARestrictedPath=A restricted path
SwaggerDescriptionFile=Swagger API description file (for use with redoc for example)
CheckForModuleUpdate=Check for modules updates
CheckForModuleUpdateHelp=Check for modules updates.<br/>This action will connect to modules editors to check if a new version is available.
ModuleUpdateAvailable=An update is available for this module
SwaggerDescriptionFile=Swagger API description file (for use with redoc for example)

View File

@ -297,3 +297,4 @@ WarningAvailableOnlyForHTTPSServers=Available only if using HTTPS secured connec
WarningModuleXDisabledSoYouMayMissEventHere=Module %s has not been enabled. So you may miss a lot of event here.
ErrorActionCommPropertyUserowneridNotDefined=User's owner is required
ErrorActionCommBadType=Selected event type (id: %n, code: %s) do not exist in Event Type dictionary
CheckVersionFail=Version check fail

View File

@ -279,6 +279,11 @@ div.pagination li:first-child a.btnTitle{
margin-left: 10px;
}
.button-title-separator{
display: inline-block;
clear: both;
width: 20px;
}
.imgforviewmode {
color: #aaa;

View File

@ -9,10 +9,14 @@ if (!defined('ISLOADEDBYSTEELSHEET')) {
* -------------------
*/
.info-box-module-external span.info-box-icon-version {
.info-box-module.--external span.info-box-icon-version {
background: #bbb;
}
.info-box-module.--external.--need-update span.info-box-icon-version{
background: #bc9525;
}
.info-box {
display: block;
position: relative;
@ -153,7 +157,7 @@ a.info-box-text-a i.fa.fa-exclamation-triangle {
-webkit-transition: opacity 0.5s, visibility 0s 0.5s;
transition: opacity 0.5s, visibility 0s 0.5s;
}
.box-flex-item.info-box-module.info-box-module-disabled {
.box-flex-item.info-box-module.--disabled {
/* opacity: 0.6; */
}

View File

@ -119,7 +119,7 @@ if (GETPOSTISSET('THEME_SATURATE_RATIO')) {
}
.info-box-module-external span.info-box-icon-version {
.info-box-module.--external span.info-box-icon-version {
background: #bbb;
}
@ -250,7 +250,7 @@ a.info-box-text-a i.fa.fa-exclamation-triangle {
transition: opacity 0.5s, visibility 0s 0.5s;
}
.box-flex-item.info-box-module.info-box-module-disabled {
.box-flex-item.info-box-module.--disabled {
/* opacity: 0.6; */
}