diff --git a/lizmap/plugin.py b/lizmap/plugin.py index 15acd3f1..53ff16ec 100755 --- a/lizmap/plugin.py +++ b/lizmap/plugin.py @@ -107,10 +107,10 @@ from lizmap.lizmap_api.config import LizmapConfig from lizmap.ogc_project_validity import OgcProjectValidity from lizmap.project_checker_tools import ( + auto_generated_primary_key_field, duplicated_layer_name_or_group, duplicated_layer_with_filter, invalid_int8_primary_key, - invalid_tid_field, simplify_provider_side, use_estimated_metadata, ) @@ -2683,60 +2683,70 @@ def project_config_file(self, lwc_version: LwcVersions, with_gui: bool = True, c message += "
" message += tr( - "The process is continuing but expect some layers to not be visible in Lizmap Web Client.") + "The process is continuing but expect these layers to not be visible in Lizmap Web Client.") ScrollMessageBox(self.dlg, QMessageBox.Warning, tr('Lizmap.com hosting'), message) + show_log = False if check_server: - results = { - 'tid': [], - 'int8': [], - } + autogenerated_keys = {} + int8 = [] for layer in self.project.mapLayers().values(): + if not isinstance(layer, QgsVectorLayer): continue - if invalid_tid_field(layer): - results['tid'].append(layer.name()) - if invalid_int8_primary_key(layer): - results['int8'].append(layer.name()) - message = tr('Some fields are invalid for QGIS server.') + '
' - end = tr("We highly recommend you to set a proper integer field, but neither a bigint nor an integer8 :") - - if results['tid']: - message += tr( - "The field 'tid' has been detected as primary key for your layer but it wasn't found in the layer " - "fields.") + " " - message += end - message += "

" + result, field = auto_generated_primary_key_field(layer) + if result: + if field not in autogenerated_keys.keys(): + autogenerated_keys[field] = [] - if results['int8']: - message += tr("The primary key has been detected as a bigint (integer8) for your layer.") + " " - message += end - message += "

" + autogenerated_keys[field].append(layer.name()) - message += "
" - message += tr( - "The process is continuing but expect some layers to not be visible in Lizmap Web Client.") + if invalid_int8_primary_key(layer): + int8.append(layer.name()) - if results['tid'] or results['int8']: + if autogenerated_keys or int8: + show_log = True warnings.append(Warnings.InvalidFieldType.value) - ScrollMessageBox(self.dlg, QMessageBox.Warning, tr('QGIS server'), message) + self.dlg.log_panel.append(tr('Some fields are invalid for QGIS server'), Html.H2) + + for field, layers in autogenerated_keys.items(): + # field can be "tid", "ctid" etc + self.dlg.log_panel.append(tr( + "These layers don't have a proper primary key in the database. So QGIS Desktop tried to set a " + "temporary field called '{}' to be a unique identifier. On QGIS Server, this will bring issues." + ).format(field)) + self.dlg.log_panel.append("
") + for layer_name in layers: + self.dlg.log_panel.append('⚫ {}'.format(layer_name)) + self.dlg.log_panel.append("
") + + if int8: + self.dlg.log_panel.append(tr( + "The primary key has been detected as a bigint (integer8) for your layer :")) + self.dlg.log_panel.append("
") + for layer_name in int8: + self.dlg.log_panel.append("⚫ {}".format(layer_name)) + self.dlg.log_panel.append("
") + + self.dlg.log_panel.append("
") + self.dlg.log_panel.append(tr( + "We highly recommend you to set a proper integer field as a primary key, but neither a bigint nor an " + "integer8.")) + self.dlg.log_panel.append("
") + self.dlg.log_panel.append(tr( + "The process is continuing but expect these layers to have some issues with some tools in " + "Lizmap Web Client: zoom to feature, filtering..." + )) if lwc_version >= LwcVersions.Lizmap_3_7: text = duplicated_layer_with_filter(self.project) if text: - message += tr( + text += tr( "The process is continuing but the project might be slow in Lizmap Web Client.") warnings.append(Warnings.DuplicatedLayersWithFilters.value) ScrollMessageBox(self.dlg, QMessageBox.Warning, tr('Optimisation'), text) - show_log = False results = simplify_provider_side(self.project) if len(results): self.dlg.log_panel.append(tr('Simplify on the provider side'), Html.H2) @@ -3127,8 +3137,8 @@ def check_project_validity(self): valid, results = validator.validate(self.project) self.dlg.log_panel.append(tr("OGC validation"), style=Html.H2) self.dlg.log_panel.append(tr("According to OGC standard : {}").format('VALID' if valid else 'NOT valid')) - if not valid: - self.dlg.log_panel.append(tr("According to OGC standard : {}").format('VALID' if valid else 'NOT valid')) + # if not valid: + # self.dlg.log_panel.append(tr("According to OGC standard : {}").format('VALID' if valid else 'NOT valid')) LOGGER.info(f"Project has been detected : {'VALID' if valid else 'NOT valid'} according to OGC validation.") @@ -3376,9 +3386,9 @@ def save_cfg_file( self.dlg.cbIgnCadastral.isChecked(), ] - self.dlg.log_panel.separator() - self.dlg.log_panel.append(tr('Map - options'), Html.Strong) - self.dlg.log_panel.separator() + # self.dlg.log_panel.separator() + # self.dlg.log_panel.append(tr('Map - options'), Html.Strong) + # self.dlg.log_panel.separator() # Checking configuration data # Get the project data from api to check the "coordinate system restriction" of the WMS Server settings diff --git a/lizmap/project_checker_tools.py b/lizmap/project_checker_tools.py index b5170d6c..e4d67537 100644 --- a/lizmap/project_checker_tools.py +++ b/lizmap/project_checker_tools.py @@ -2,7 +2,7 @@ __license__ = 'GPL version 3' __email__ = 'info@3liz.org' -from typing import List, Optional +from typing import List, Optional, Tuple from qgis.core import ( QgsDataSourceUri, @@ -20,8 +20,8 @@ # https://github.com/3liz/lizmap-web-client/issues/3692 -def invalid_tid_field(layer: QgsVectorLayer) -> bool: - """ If the primary key has been detected as tid but the field does not exist. """ +def auto_generated_primary_key_field(layer: QgsVectorLayer) -> Tuple[bool, Optional[str]]: + """ If the primary key has been detected as tid/ctid but the field does not exist. """ # Example # CREATE TABLE IF NOT EXISTS public.test_tid # ( @@ -29,17 +29,17 @@ def invalid_tid_field(layer: QgsVectorLayer) -> bool: # label text # ) # In QGIS source code, look for "Primary key is ctid" - uri = QgsDataSourceUri(layer.source()) + # QgsVectorLayer.primaryKeyAttributes is returning a list. - # TODO check, but with QgsDataSourceUri, we have a single field - if uri.keyColumn() != 'tid': - return False + if len(layer.primaryKeyAttributes()) >= 2: + # We don't check for composite keys here + return False, None - if 'tid' in layer.fields().names(): - return False + if layer.dataProvider().uri().keyColumn() in layer.fields().names(): + return False, None - # The layer has "tid" as a primary key, but the field is not found. - return True + # The layer has "tid" or "ctid" as a primary key, but the field is not found. + return True, layer.dataProvider().uri().keyColumn() def invalid_int8_primary_key(layer: QgsVectorLayer) -> bool: