diff --git a/lizmap/app/system/mainconfig.ini.php b/lizmap/app/system/mainconfig.ini.php
index 03b848298e..dc287d713b 100644
--- a/lizmap/app/system/mainconfig.ini.php
+++ b/lizmap/app/system/mainconfig.ini.php
@@ -36,10 +36,10 @@
; Lizmap QGIS desktop plugin required/recommended minimum version for newly or updated project only
; This version MUST match at least on https://plugins.qgis.org/plugins/lizmap/#plugin-versions
; with the minimum QGIS server version supported above.
-; This is experimental for now.
; This value is only forwarded to the plugin thanks to the server metadata. According to the age of the project, it
; will be either recommended or required.
lizmapDesktopPlugin="4.1.8"
+lizmapDesktopPluginDate="2024-01-30"
; Versions written in QGIS/CFG files, for the GIS administrator
; Lizmap CFG files with a lower target version are not displayed in the landing page, but displayed in the administration panel to warn the GIS administrator
diff --git a/lizmap/modules/admin/locales/en_US/admin.UTF-8.properties b/lizmap/modules/admin/locales/en_US/admin.UTF-8.properties
index 3a5e50c675..1e13e7aaf6 100644
--- a/lizmap/modules/admin/locales/en_US/admin.UTF-8.properties
+++ b/lizmap/modules/admin/locales/en_US/admin.UTF-8.properties
@@ -341,6 +341,8 @@ Open the project in QGIS desktop with an updated version of the plugin
project.list.column.target.lizmap.version.label=Target version
project.list.column.target.lizmap.version.label.longer=Target version of Lizmap Web Client
project.list.column.lizmap.plugin.version.label=Lizmap plugin
+project.list.column.qgis.desktop.recent.label=This QGIS project has been recently updated in QGIS Desktop, \
+but with a too old Lizmap plugin version. You should upgrade your plugin in the QGIS plugin manager.
project.list.column.lizmap.warnings.count.label=Warnings
project.list.column.lizmap.warnings.explanations.label=Check your Lizmap plugin in QGIS Desktop to fix these warnings
project.list.column.authorized.groups.label=Groups
diff --git a/lizmap/modules/admin/templates/project_list_zone.tpl b/lizmap/modules/admin/templates/project_list_zone.tpl
index 6ffa291f8d..637cd6454a 100644
--- a/lizmap/modules/admin/templates/project_list_zone.tpl
+++ b/lizmap/modules/admin/templates/project_list_zone.tpl
@@ -181,8 +181,14 @@ to view the hidden columns data and when there is no data for these columns -->
{assign $title = $title . ' - '}
{/if}
{assign $title = $title . @admin.project.list.column.lizmap.plugin.version.label@ . ' ' . $p['lizmap_plugin_version']}
+ {if $p['lizmap_plugin_update'] }
+ {assign $title = $title . ' ' . @admin.project.list.column.qgis.desktop.recent.label@}
+ {/if}
{$p['qgis_version']}
+ {if $p['lizmap_plugin_update'] }
+ ⚠
+ {/if}
|
diff --git a/lizmap/modules/admin/zones/project_list.zone.php b/lizmap/modules/admin/zones/project_list.zone.php
index c819195ff2..3f4db57609 100644
--- a/lizmap/modules/admin/zones/project_list.zone.php
+++ b/lizmap/modules/admin/zones/project_list.zone.php
@@ -175,6 +175,7 @@ private function getProjectListItem($inspectionDirectoryPath, $projectMetadata)
'lizmap_web_client_target_version' => $projectMetadata->getLizmapWebClientTargetVersion(),
// convert int to string orderable
'lizmap_plugin_version' => $this->pluginIntVersionToSortableString($projectMetadata->getLizmapPluginVersion()),
+ 'lizmap_plugin_update' => $projectMetadata->updateQgisLizmapPlugin(),
'file_time' => $projectMetadata->getFileTime(),
'layer_count' => $projectMetadata->getLayerCount(),
'acl_groups' => $projectMetadata->getAclGroups(),
diff --git a/lizmap/modules/lizmap/lib/Project/Project.php b/lizmap/modules/lizmap/lib/Project/Project.php
index 6f10ef9b50..e1adf58271 100644
--- a/lizmap/modules/lizmap/lib/Project/Project.php
+++ b/lizmap/modules/lizmap/lib/Project/Project.php
@@ -327,6 +327,16 @@ public function getQgisProjectVersion()
return $this->qgis->getQgisProjectVersion();
}
+ /**
+ * Get the last date saved in the QGIS file.
+ *
+ * @return string last saved date time of the file
+ */
+ public function getLastSaveDateTime()
+ {
+ return $this->qgis->getLastSaveDateTime();
+ }
+
/**
* Get the version of the Lizmap plugin
* used by the project editor on QGIS Desktop.
@@ -2359,6 +2369,17 @@ public function needsUpdateWarning()
return false;
}
+ /**
+ * Project needs an update on plugin side.
+ * The check is done only is the QGIS file has been edited recently.
+ *
+ * @return bool true if the plugin needs to be updated
+ */
+ public function updateQgisLizmapPlugin()
+ {
+ return $this->getMetadata()->updateQgisLizmapPlugin();
+ }
+
/**
* Project warnings in the CFG file.
*
diff --git a/lizmap/modules/lizmap/lib/Project/ProjectMetadata.php b/lizmap/modules/lizmap/lib/Project/ProjectMetadata.php
index 1aa71ac2cc..1117f59791 100644
--- a/lizmap/modules/lizmap/lib/Project/ProjectMetadata.php
+++ b/lizmap/modules/lizmap/lib/Project/ProjectMetadata.php
@@ -41,6 +41,7 @@ public function __construct(Project $project)
'map' => $project->getRelativeQgisPath(),
'acl' => $project->checkAcl(),
'qgisProjectVersion' => $project->getQgisProjectVersion(),
+ 'lastSaveDateTime' => $project->getLastSaveDateTime(),
'lizmapPluginVersion' => $project->getLizmapPluginVersion(),
'lizmapWebClientTargetVersion' => $project->getLizmapWebCLientTargetVersion(),
'needsUpdateError' => $project->needsUpdateError(),
@@ -181,6 +182,16 @@ public function getWMTSGetCapabilitiesUrl()
return $this->data['wmtsGetCapabilitiesUrl'];
}
+ /**
+ * The last save date time of the QGIS file.
+ *
+ * @return string the last save date time
+ */
+ public function getLastSaveDateTime()
+ {
+ return $this->data['lastSaveDateTime'];
+ }
+
/**
* The QGIS desktop project version.
*
@@ -211,6 +222,56 @@ public function getLizmapWebCLientTargetVersion()
return $this->data['lizmapWebClientTargetVersion'];
}
+ /**
+ * If the QGIS desktop needs an update of the plugin.
+ * The check is not done only if the project has been edited recently compare to the date of the Lizmap Web Client.
+ *
+ * @return bool If the plugin should be updated in QGIS Desktop
+ */
+ public function updateQgisLizmapPlugin()
+ {
+ // Not the best choice, maybe because of git for dev, dates are not correct
+ // $projectDate = date($this->getFileTime());
+ // Better to use lastSaveDateTime in the QGS file
+ $projectDate = strtotime($this->getLastSaveDateTime());
+
+ // Which date to use for reference ?
+ // LWC date is too old. For 3.8 for instance, for dev, it's currently 2023-11-24
+ // But for LWC 3.7, it's ok because we have frequent releases now.
+ // $projectInfos = \Jelix\Core\Infos\AppInfos::load();
+ // $releaseDate = $projectInfos->versionDate;
+ // So let's use a date matching the plugin version
+ $releaseDate = \jApp::config()->minimumRequiredVersion['lizmapDesktopPluginDate'];
+
+ if ($projectDate < strtotime($releaseDate)) {
+ // Project file date is older than internal release date, we do nothing
+ // Project can stay on the server without any update
+ return false;
+ }
+
+ // Project file is newer than the release date
+ // We check against the hard coded version
+ $recommendedVersion = \jApp::config()->minimumRequiredVersion['lizmapDesktopPlugin'];
+
+ $projectVersion = $this->getLizmapPluginVersion();
+ if (!is_numeric($projectVersion)) {
+ // It shouldn't happen to much, but before the version was like "master".
+ return false;
+ }
+
+ // TODO It would be nice to avoid code duplication,
+ // we have code to manage versions for sorting, display, integer comparaison...
+ $intVersion6Digit = (strlen($projectVersion) == 6 ? $projectVersion : '0'.$projectVersion);
+ list($majorVersion, $minorVersion, $patchVersion) = str_split($intVersion6Digit, 2);
+
+ if (version_compare($majorVersion.'.'.$minorVersion.'.'.$patchVersion, $recommendedVersion) >= 0) {
+ // Lizmap plugin version in the CFG file is newer than the hard coded version
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Check if the project needs an update which is critical.
*
diff --git a/lizmap/modules/lizmap/lib/Project/QgisProject.php b/lizmap/modules/lizmap/lib/Project/QgisProject.php
index 1c317669df..25784115e3 100644
--- a/lizmap/modules/lizmap/lib/Project/QgisProject.php
+++ b/lizmap/modules/lizmap/lib/Project/QgisProject.php
@@ -39,6 +39,13 @@ class QgisProject
*/
protected $qgisProjectVersion;
+ /**
+ * Last saved date time in the QGIS file.
+ *
+ * @var string
+ */
+ protected $lastSaveDateTime;
+
/**
* @var array contains WMS info
*/
@@ -105,6 +112,7 @@ class QgisProject
'layers',
'data',
'qgisProjectVersion',
+ 'lastSaveDateTime',
'customProjectVariables',
);
@@ -225,6 +233,16 @@ public function getQgisProjectVersion()
return $this->qgisProjectVersion;
}
+ /**
+ * Last saved date time in the QGIS file.
+ *
+ * @return string
+ */
+ public function getLastSaveDateTime()
+ {
+ return $this->lastSaveDateTime;
+ }
+
public function getWMSInformation()
{
return $this->WMSInformation;
@@ -1192,6 +1210,7 @@ protected function readXmlProject($qgs_path)
// get QGIS project version
$this->qgisProjectVersion = $this->readQgisProjectVersion($qgsXml);
+ $this->lastSaveDateTime = $this->readLastSaveDateTime($qgsXml);
$this->WMSInformation = $this->readWMSInformation($qgsXml);
$this->canvasColor = $this->readCanvasColor($qgsXml);
@@ -1259,6 +1278,21 @@ protected function readWMSInformation($qgsLoad)
);
}
+ /**
+ * Read the last modified date of the QGS file.
+ *
+ * @param \SimpleXMLElement $xml
+ *
+ * @return string
+ */
+ protected function readLastSaveDateTime($xml)
+ {
+ $qgisRoot = $xml->xpath('//qgis');
+ $qgisRootZero = $qgisRoot[0];
+
+ return (string) $qgisRootZero->attributes()->saveDateTime;
+ }
+
/**
* @param \SimpleXMLElement $xml
*/
diff --git a/lizmap/modules/view/controllers/lizMap.classic.php b/lizmap/modules/view/controllers/lizMap.classic.php
index 394a9588bd..e93fd08358 100644
--- a/lizmap/modules/view/controllers/lizMap.classic.php
+++ b/lizmap/modules/view/controllers/lizMap.classic.php
@@ -567,7 +567,7 @@ function f($x)
}
$serverInfoAccess = (\jAcl2::check('lizmap.admin.access') || \jAcl2::check('lizmap.admin.server.information.view'));
- if ($serverInfoAccess && $lproj->projectCountCfgWarnings() >= 1) {
+ if ($serverInfoAccess && ($lproj->projectCountCfgWarnings() >= 1 || $lproj->updateQgisLizmapPlugin())) {
$jsWarning = "
lizMap.events.on(
{
diff --git a/tests/units/README.md b/tests/units/README.md
index 51aa115fd0..1c5cdad834 100644
--- a/tests/units/README.md
+++ b/tests/units/README.md
@@ -1,11 +1,11 @@
Unit tests for Lizmap
=====================
-A unit tests shoud be added each time you fix a bug or provide a new feature / API.
+A unit tests should be added each time you fix a bug or provide a new feature / API.
-- testslib directory: where classes inheriting from Lizmap classes or new classes
+- `testslib` directory: where classes inheriting from Lizmap classes or new classes
for tests are stored.
No need to do a `require`. These classes are autoloaded, if their name ends
with `ForTests`.
-- tmp: use this directory to store temporary content for your tests
+- `tmp`: use this directory to store temporary content for your tests
- Other directories : they contain tests.
diff --git a/tests/units/classes/Project/QgisProjectTest.php b/tests/units/classes/Project/QgisProjectTest.php
index 24b7ce1865..6509f646e6 100644
--- a/tests/units/classes/Project/QgisProjectTest.php
+++ b/tests/units/classes/Project/QgisProjectTest.php
@@ -234,6 +234,19 @@ public function testReadLayers()
}
}
+ public function testReadQgisMetadata()
+ {
+ $testQgis = new qgisProjectForTests();
+ $xml = simplexml_load_file(__DIR__.'/Ressources/readLayers_316.qgs');
+ $this->assertEquals('31607', $testQgis->readQgisVersionForTests($xml));
+ $this->assertEquals('2021-06-14T11:50:51', $testQgis->readLastSaveDateTimeForTests($xml));
+
+ $testQgis = new qgisProjectForTests();
+ $xml = simplexml_load_file(__DIR__.'/Ressources/readLayers_310.qgs');
+ $this->assertEquals('31004', $testQgis->readQgisVersionForTests($xml));
+ $this->assertEquals('', $testQgis->readLastSaveDateTimeForTests($xml));
+ }
+
public function testReadRelations()
{
$expectedRelations = array(
diff --git a/tests/units/testslib/QgisProjectForTests.php b/tests/units/testslib/QgisProjectForTests.php
index e85e743df0..ea4bb2a9cd 100644
--- a/tests/units/testslib/QgisProjectForTests.php
+++ b/tests/units/testslib/QgisProjectForTests.php
@@ -66,6 +66,16 @@ public function readLayersForTests($xml)
return $this->readLayers($xml);
}
+ public function readQgisVersionForTests($xml)
+ {
+ return $this->readQgisProjectVersion($xml);
+ }
+
+ public function readLastSaveDateTimeForTests($xml)
+ {
+ return $this->readLastSaveDateTime($xml);
+ }
+
public function readRelationsForTests($xml)
{
$this->xml = $xml;