diff --git a/lizmap/definitions/attribute_table.py b/lizmap/definitions/attribute_table.py
index 483a957b..fd87002a 100755
--- a/lizmap/definitions/attribute_table.py
+++ b/lizmap/definitions/attribute_table.py
@@ -2,9 +2,10 @@
from qgis.core import QgsAttributeTableConfig, QgsVectorLayer
from lizmap.definitions.base import BaseDefinitions, InputType
+from lizmap.definitions.definitions import LwcVersions
from lizmap.toolbelt.i18n import tr
-__copyright__ = 'Copyright 2020, 3Liz'
+__copyright__ = 'Copyright 2025, 3Liz'
__license__ = 'GPL version 3'
__email__ = 'info@3liz.org'
@@ -41,6 +42,21 @@ def __init__(self):
'default': '',
'tooltip': tr('List of fields to hide in the attribute table.')
}
+ self._layer_config['export_enabled'] = {
+ 'type': InputType.CheckBox,
+ 'header': tr('Export enabled'),
+ 'default': True,
+ 'tooltip': tr('If the export of the layer is enabled.'),
+ 'version': LwcVersions.Lizmap_3_9,
+ 'use_json': True,
+ }
+ self._layer_config['export_allowed_groups'] = {
+ 'type': InputType.Text,
+ 'header': tr('Allowed groups for export'),
+ 'default': '',
+ 'tooltip': tr('Allowed list of groups for exporting the data. If empty, everyone can export the data.'),
+ 'version': LwcVersions.Lizmap_3_9,
+ }
self._layer_config['pivot'] = {
'type': InputType.CheckBox,
'header': tr('Pivot table'),
diff --git a/lizmap/forms/attribute_table_edition.py b/lizmap/forms/attribute_table_edition.py
index 111df566..cdd700f4 100755
--- a/lizmap/forms/attribute_table_edition.py
+++ b/lizmap/forms/attribute_table_edition.py
@@ -1,6 +1,7 @@
"""Dialog for attribute table edition."""
from qgis.core import QgsMapLayerProxyModel
+from qgis.PyQt.QtGui import QIcon
from lizmap.definitions.attribute_table import (
AttributeTableDefinitions,
@@ -9,9 +10,9 @@
from lizmap.definitions.definitions import LwcVersions
from lizmap.forms.base_edition_dialog import BaseEditionDialog
from lizmap.toolbelt.i18n import tr
-from lizmap.toolbelt.resources import load_ui
+from lizmap.toolbelt.resources import load_ui, resources_path
-__copyright__ = 'Copyright 2020, 3Liz'
+__copyright__ = 'Copyright 2025, 3Liz'
__license__ = 'GPL version 3'
__email__ = 'info@3liz.org'
@@ -28,6 +29,8 @@ def __init__(self, parent=None, unicity=None, lwc_version: LwcVersions = None):
self.config.add_layer_widget('layerId', self.layer)
self.config.add_layer_widget('primaryKey', self.primary_key)
self.config.add_layer_widget('hiddenFields', self.fields_to_hide)
+ self.config.add_layer_widget('export_enabled', self.export_enabled)
+ self.config.add_layer_widget('export_allowed_groups', self.export_allowed_groups)
self.config.add_layer_widget('pivot', self.pivot_table)
self.config.add_layer_widget('hideAsChild', self.hide_subpanels)
self.config.add_layer_widget('hideLayer', self.hide_layer)
@@ -36,6 +39,8 @@ def __init__(self, parent=None, unicity=None, lwc_version: LwcVersions = None):
self.config.add_layer_label('layerId', self.label_layer)
self.config.add_layer_label('primaryKey', self.label_primary_key)
self.config.add_layer_label('hiddenFields', self.label_fields_to_hide)
+ self.config.add_layer_label('export_enabled', self.label_export_enabled)
+ self.config.add_layer_label('export_allowed_groups', self.label_export_allowed_groups)
self.config.add_layer_label('pivot', self.label_pivot_table)
self.config.add_layer_label('hideAsChild', self.label_hide_subpanels)
self.config.add_layer_label('hideLayer', self.label_hide_layer)
@@ -51,6 +56,15 @@ def __init__(self, parent=None, unicity=None, lwc_version: LwcVersions = None):
self.fields_to_hide.set_layer(self.layer.currentLayer())
self.setup_ui()
+
+ # Wizard ACL group
+ self.export_enabled.stateChanged.connect(self.export_allowed_groups.setEnabled)
+ icon = QIcon(resources_path('icons', 'user_group.svg'))
+ self.button_wizard_group.setText('')
+ self.button_wizard_group.setIcon(icon)
+ self.button_wizard_group.clicked.connect(self.open_wizard_group)
+ self.button_wizard_group.setToolTip(tr("Open the group wizard"))
+
self.check_layer_wfs()
self.enable_primary_key_field()
@@ -64,6 +78,15 @@ def check_layer_wfs(self):
not_in_wfs = self.is_layer_in_wfs(layer)
self.show_error(not_in_wfs)
+ def open_wizard_group(self):
+ """ When the user clicks on the group wizard. """
+ layer = self.layer.currentLayer()
+ if not layer:
+ return
+
+ helper = tr("Setting groups for the layer exporting capabilities '{}'").format(layer.name())
+ super().open_wizard_dialog(helper)
+
def post_load_form(self):
self.layer_changed()
diff --git a/lizmap/forms/base_edition_dialog.py b/lizmap/forms/base_edition_dialog.py
index 66f60cd7..953bb415 100755
--- a/lizmap/forms/base_edition_dialog.py
+++ b/lizmap/forms/base_edition_dialog.py
@@ -23,7 +23,7 @@
from lizmap.qt_style_sheets import NEW_FEATURE_COLOR, NEW_FEATURE_CSS
from lizmap.toolbelt.i18n import tr
-__copyright__ = 'Copyright 2023, 3Liz'
+__copyright__ = 'Copyright 2025, 3Liz'
__license__ = 'GPL version 3'
__email__ = 'info@3liz.org'
@@ -61,6 +61,7 @@ def __init__(self, parent: QDialog = None, unicity=None, lwc_version: LwcVersion
self.lwc_versions[LwcVersions.Lizmap_3_6] = []
self.lwc_versions[LwcVersions.Lizmap_3_7] = []
self.lwc_versions[LwcVersions.Lizmap_3_8] = []
+ self.lwc_versions[LwcVersions.Lizmap_3_9] = []
def setup_ui(self):
""" Build the UI. """
diff --git a/lizmap/resources/ui/ui_form_attribute_table.ui b/lizmap/resources/ui/ui_form_attribute_table.ui
index a0ef33a4..95e85999 100755
--- a/lizmap/resources/ui/ui_form_attribute_table.ui
+++ b/lizmap/resources/ui/ui_form_attribute_table.ui
@@ -6,8 +6,8 @@
0
0
- 425
- 303
+ 554
+ 390
@@ -43,6 +43,9 @@
+ -
+
+
-
@@ -71,6 +74,13 @@
+ -
+
+
+ Hide layer in the list
+
+
+
-
@@ -81,16 +91,13 @@
- -
-
+
-
+
- Hide layer in the list
+ Has a custom config
- -
-
-
-
@@ -98,10 +105,38 @@
- -
-
+
-
+
- Has a custom config
+ Export allowed groups
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
-
+
+
+ -
+
+
+ WIZARD
+
+
+
+
+
+ -
+
+
+ Export enabled
diff --git a/lizmap/test/test_table_manager.py b/lizmap/test/test_table_manager.py
index e4cd1a92..ee5a425f 100755
--- a/lizmap/test/test_table_manager.py
+++ b/lizmap/test/test_table_manager.py
@@ -991,6 +991,43 @@ def test_attribute_table(self):
# Automatically added, so we add it manually for the comparaison
json['lines']['custom_config'] = 'False'
+ # Allowing groups for exporting
+ json['lines']['export_enabled'] = True
+ self.assertIsNone(json['lines'].get('export_allowed_groups'))
+
+ self.assertDictEqual(data, json)
+
+ self.assertDictEqual({self.layer.id(): ['id']}, table_manager.wfs_fields_used())
+
+ def test_attribute_table_export_acl(self):
+ """Test table manager with attribute table with export ACL"""
+ table = QTableWidget()
+ definitions = AttributeTableDefinitions()
+
+ table_manager = TableManager(
+ None, definitions, None, table, None, None, None, None)
+
+ json = {
+ 'lines': {
+ 'primaryKey': 'id',
+ 'export_enabled': True,
+ 'export_allowed_groups': 'admins',
+ 'hiddenFields': 'id,name,value',
+ 'pivot': 'False',
+ 'hideAsChild': 'False',
+ 'hideLayer': 'False',
+ 'layerId': self.layer.id(),
+ 'order': 0
+ }
+ }
+ self.assertEqual(table_manager.table.rowCount(), 0)
+ table_manager.from_json(json)
+ self.assertEqual(table_manager.table.rowCount(), 1)
+ data = table_manager.to_json(LwcVersions.latest())
+
+ # Automatically added, so we add it manually for the comparaison
+ json['lines']['custom_config'] = 'False'
+
self.assertDictEqual(data, json)
self.assertDictEqual({self.layer.id(): ['id']}, table_manager.wfs_fields_used())