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;