diff --git a/g3w-admin/editing/forms.py b/g3w-admin/editing/forms.py
index 44cba7e92..4e7fe4a37 100644
--- a/g3w-admin/editing/forms.py
+++ b/g3w-admin/editing/forms.py
@@ -83,6 +83,20 @@ class ActiveEditingLayerForm(ActiveEditingMixin, G3WRequestFormMixin, G3WProject
#' more than 200 characters long.
'
'Value stored into the field it will be so structured: '
'[username]'))
+ add_user_group_field = forms.ChoiceField(choices=[], label=_('User Groups adding data field'), required=False,
+ help_text=_('Optional: select layer field to store '
+ 'user groups name that entered the data. '
+ 'Showed only string field.
'
+ # 'more than 200 characters long.
'
+ 'Value stored into the field it will be so structured: '
+ '[user group name 1, user group name 2, ...]'))
+ edit_user_group_field = forms.ChoiceField(choices=[], label=_('User Groups editing data field'), required=False,
+ help_text=_('Optional: select layer field to store '
+ 'user groups name that updated the data. '
+ 'Showed only string field.
'
+ # ' more than 200 characters long.
'
+ 'Value stored into the field it will be so structured: '
+ '[user group name 1, user group name 2, ...]'))
def __init__(self, *args, **kwargs):
@@ -117,6 +131,8 @@ def __init__(self, *args, **kwargs):
layout_args += [
Field('add_user_field', css_class='select2', style="width:100%;"),
Field('edit_user_field', css_class='select2', style="width:100%;"),
+ Field('add_user_group_field', css_class='select2', style="width:100%;"),
+ Field('edit_user_group_field', css_class='select2', style="width:100%;"),
HTML(_('Select viewers with \'view permission\' on project that can edit layer:')),
Field('viewer_users', css_class='select2', style="width:100%;"),
Div(css_class='users_atomic_capabilities'),
@@ -126,19 +142,56 @@ def __init__(self, *args, **kwargs):
self.helper.layout = Layout(*layout_args)
+ def clean_add_user_field(self):
+
+ # Create general error message
+ self.logging_fields_except = ValidationError(_("'User adding data field' and 'User editing data field' and "
+ "'User group adding data field' and 'User group editing data field' "
+ "must be unique."))
+
+ if self.cleaned_data['add_user_field'] and self.cleaned_data['add_user_field'] in (
+ self.data.get('edit_user_field', None),
+ self.data.get('add_user_group_field', None),
+ self.data.get('edit_user_group_field', None)):
+ raise self.logging_fields_except
+
+ return self.cleaned_data['add_user_field']
+
def clean_edit_user_field(self):
- if self.cleaned_data['edit_user_field'] and self.cleaned_data['add_user_field']:
- if self.cleaned_data['edit_user_field'] == self.cleaned_data['add_user_field']:
- raise ValidationError(_("'User adding data field' and 'User editing data field' "
- "cannot assume the same value."))
+ if self.cleaned_data['edit_user_field'] and self.cleaned_data['edit_user_field'] in (
+ self.data.get('add_user_field', None),
+ self.data.get('add_user_group_field', None),
+ self.data.get('edit_user_group_field', None)):
+ raise self.logging_fields_except
return self.cleaned_data['edit_user_field']
+ def clean_add_user_group_field(self):
+
+ if self.cleaned_data['add_user_group_field'] and self.cleaned_data['add_user_group_field'] in (
+ self.data.get('edit_user_field', None),
+ self.data.get('add_user_field', None),
+ self.data.get('edit_user_group_field', None)):
+ raise self.logging_fields_except
+
+ return self.cleaned_data['add_user_group_field']
+
+ def clean_edit_user_group_field(self):
+
+ if self.cleaned_data['edit_user_group_field'] and self.cleaned_data['edit_user_group_field'] in (
+ self.data.get('edit_user_field', None),
+ self.data.get('add_user_field', None),
+ self.data.get('add_user_group_field', None)):
+ raise self.logging_fields_except
+
+ return self.cleaned_data['edit_user_group_field']
+
def _set_add_edit_user_field_choices(self):
"""
- Set choices for add_user_field select and edit_user_field select
+ Set choices for add_user_field select and edit_user_field select and for
+ add_user_group_field, edit_user_group_field.
"""
touse = []
@@ -152,6 +205,9 @@ def _set_add_edit_user_field_choices(self):
self.fields['edit_user_field'].choices = \
self.fields['add_user_field'].choices = [(None, '--------')] + [(f, f) for f in touse]
+ self.fields['edit_user_group_field'].choices = \
+ self.fields['add_user_group_field'].choices = [(None, '--------')] + [(f, f) for f in touse]
+
class ActiveEditingMultiLayerForm(ActiveEditingMixin, G3WRequestFormMixin, G3WProjectFormMixin, forms.Form):
"""
@@ -174,6 +230,7 @@ class ActiveEditingMultiLayerForm(ActiveEditingMixin, G3WRequestFormMixin, G3WPr
label=_('User viewer groups')
)
+
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
diff --git a/g3w-admin/editing/migrations/0014_auto_20241022_0657.py b/g3w-admin/editing/migrations/0014_auto_20241022_0657.py
new file mode 100644
index 000000000..cc72e25e3
--- /dev/null
+++ b/g3w-admin/editing/migrations/0014_auto_20241022_0657.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.25 on 2024-10-22 06:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('editing', '0013_g3weditinglayer_visible'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='g3weditinglayer',
+ name='add_user_group_field',
+ field=models.TextField(blank=True, null=True),
+ ),
+ migrations.AddField(
+ model_name='g3weditinglayer',
+ name='edit_user_group_field',
+ field=models.TextField(blank=True, null=True),
+ ),
+ ]
diff --git a/g3w-admin/editing/migrations/0015_auto_20241022_0707.py b/g3w-admin/editing/migrations/0015_auto_20241022_0707.py
new file mode 100644
index 000000000..c480bbdbe
--- /dev/null
+++ b/g3w-admin/editing/migrations/0015_auto_20241022_0707.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.25 on 2024-10-22 07:07
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('editing', '0014_auto_20241022_0657'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='g3weditinglayer',
+ name='add_user_group_field',
+ field=models.CharField(blank=True, max_length=255, null=True),
+ ),
+ migrations.AlterField(
+ model_name='g3weditinglayer',
+ name='edit_user_group_field',
+ field=models.CharField(blank=True, max_length=255, null=True),
+ ),
+ ]
diff --git a/g3w-admin/editing/models/editing.py b/g3w-admin/editing/models/editing.py
index b6eb4f189..adabfb3ce 100644
--- a/g3w-admin/editing/models/editing.py
+++ b/g3w-admin/editing/models/editing.py
@@ -43,6 +43,8 @@ class G3WEditingLayer(models.Model):
add_user_field = models.CharField(null=True, blank=True, max_length=255)
edit_user_field = models.CharField(null=True, blank=True, max_length=255)
visible = models.BooleanField(default=True, null=True, blank=True, help_text="Show layer in layers list to edit")
+ add_user_group_field = models.CharField(null=True, blank=True, max_length=255)
+ edit_user_group_field = models.CharField(null=True, blank=True, max_length=255)
class Meta:
app_label = 'editing'
diff --git a/g3w-admin/editing/receivers.py b/g3w-admin/editing/receivers.py
index 5e525f7ba..f61f7700f 100644
--- a/g3w-admin/editing/receivers.py
+++ b/g3w-admin/editing/receivers.py
@@ -26,6 +26,7 @@
)
from qdjango.vector import LayerVectorView, MODE_CONFIG
from qdjango.models import GeoConstraintRule
+from usersmanage.utils import get_user_groups
from .models import (
G3WEditingFeatureLock,
G3WEditingLayer,
@@ -315,24 +316,52 @@ def fill_logging_fields(sender, **kwargs):
mode = kwargs["mode"]
user = kwargs["user"]
+ user_groups = ", ".join([g.name for g in get_user_groups(user)])
try:
el = G3WEditingLayer.objects.get(
app_name="qdjango", layer_id=kwargs["layer_metadata"].layer_id
)
- if el.add_user_field and mode == EDITING_POST_DATA_ADDED:
- kwargs["data"]["feature"]["properties"][
- el.add_user_field
- ] = f"{user.username}"
+ if mode == EDITING_POST_DATA_ADDED:
- # Remove edit_suer_field property if is active
+ # Set the user and user group
+ # ---------------------------
+ if el.add_user_field:
+ kwargs["data"]["feature"]["properties"][
+ el.add_user_field
+ ] = f"{user.username}"
+
+ # Remove edit_user_field property if is active
+ if el.edit_user_field:
+ del kwargs["data"]["feature"]["properties"][el.edit_user_field]
+
+ if el.add_user_group_field:
+ kwargs["data"]["feature"]["properties"][
+ el.add_user_group_field
+ ] = f"{user_groups}"
+
+ # Remove edit_user_field property if is active
+ if el.edit_user_group_field:
+ del kwargs["data"]["feature"]["properties"][el.edit_user_group_field]
+
+
+ if mode == EDITING_POST_DATA_UPDATED:
+
+ # Set the user and user group
+ # ---------------------------
if el.edit_user_field:
- del kwargs["data"]["feature"]["properties"][el.edit_user_field]
- if el.edit_user_field and mode == EDITING_POST_DATA_UPDATED:
- kwargs['data']['feature']['properties'][el.edit_user_field] = f"{user.username}"
+ kwargs['data']['feature']['properties'][el.edit_user_field] = f"{user.username}"
+
+ # Remove add_user_field property if is active
+ if el.add_user_field:
+ del(kwargs['data']['feature']['properties'][el.add_user_field])
+
+ if el.edit_user_group_field:
+ kwargs['data']['feature']['properties'][el.edit_user_group_field] = f"{user_groups}"
+
+ # Remove add_user_field property if is active
+ if el.add_user_group_field:
+ del (kwargs['data']['feature']['properties'][el.add_user_group_field])
- # Remove add_user_field property if is active
- if el.add_user_field:
- del(kwargs['data']['feature']['properties'][el.add_user_field])
except Exception as e:
logger.error(f"[EDITING] - FILL LOGGING FIELDS: {e}")
diff --git a/g3w-admin/editing/tests/data/logging_test.db b/g3w-admin/editing/tests/data/logging_test.db
index 08ea2f2dd..3af39dc89 100644
Binary files a/g3w-admin/editing/tests/data/logging_test.db and b/g3w-admin/editing/tests/data/logging_test.db differ
diff --git a/g3w-admin/editing/tests/test_api.py b/g3w-admin/editing/tests/test_api.py
index 19ac43d17..466e586b4 100644
--- a/g3w-admin/editing/tests/test_api.py
+++ b/g3w-admin/editing/tests/test_api.py
@@ -997,7 +997,7 @@ def test_editing_fields_loggin_commit_mode_api(self):
editing_layer = self.logging_project.instance.layer_set.all()[0]
# Activate logging field
- G3WEditingLayer.objects.create(app_name='qdjango', layer_id=editing_layer.pk,
+ el = G3WEditingLayer.objects.create(app_name='qdjango', layer_id=editing_layer.pk,
add_user_field='insert_log', edit_user_field='update_log')
# ADD
@@ -1091,6 +1091,114 @@ def test_editing_fields_loggin_commit_mode_api(self):
self.assertTrue(f'admin01' in qgs_feature.attribute('insert_log'))
self.assertTrue(f'admin01' in qgs_feature.attribute('update_log'))
+ self.client.logout()
+
+ # TEST AS TEST_USER4 (VIEWER)
+ # -----------------------------------------------------------------
+ assign_perm('view_project', self.test_user4, self.logging_project.instance)
+ self.client.login(username=self.test_user4.username, password=self.test_user4.username)
+
+ el.add_user_field = ''
+ el.add_user_group_field = 'insert_log'
+ el.edit_user_field = ''
+ el.edit_user_group_field = 'update_log'
+
+ el.save()
+
+ # Set permission for user
+ assign_perm('add_feature', self.test_user4, editing_layer)
+ assign_perm('change_feature', self.test_user4, editing_layer)
+ assign_perm('delete_feature', self.test_user4, editing_layer)
+ assign_perm('change_attr_feature', self.test_user4, editing_layer)
+ assign_perm('change_layer', self.test_user4, editing_layer)
+
+ # INSERT
+ # ======
+ payload = {
+ "add": [
+ {
+ "type": "Feature",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ -18219.126089871206,
+ -9298.036763106677
+ ]
+ },
+ "properties": {
+ "name": "test data 3",
+ "insert_log": None,
+ "update_log": None
+ },
+ "id": "_new_76_1648018518851"
+ }
+ ],
+ "update": [],
+ "delete": [],
+ "relations": {},
+ "lockids": []
+ }
+
+ response = self.client.post(commit_path, payload, format='json')
+ self.assertEqual(response.status_code, 200)
+
+ jresult = json.loads(response.content)
+ self.assertTrue(jresult['result'])
+
+ newid = jresult['response']['new'][0]['id']
+ newlockid = jresult['response']['new_lockids'][0]['lockid']
+
+ qgs_feature = editing_layer.qgis_layer.getFeature(int(newid))
+
+ self.assertTrue(f'Viewer user group1' in qgs_feature.attribute('insert_log'))
+ self.assertFalse(qgs_feature.attribute('update_log'))
+
+ # UPDATE
+ # ======
+
+ payload = {
+ "update": [
+ {
+ "type": "Feature",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ -18219.126089871206,
+ -9298.036763106677
+ ]
+ },
+ "properties": {
+ "name": "test data 3",
+ "insert_log": None,
+ "update_log": None
+ },
+ "id": newid
+ }
+ ],
+ "add": [],
+ "delete": [],
+ "relations": {},
+ "lockids": [
+ {
+ "featureid": newid,
+ "lockid": newlockid
+ }
+ ],
+ }
+
+ response = self.client.post(commit_path, payload, format='json')
+ self.assertEqual(response.status_code, 200)
+
+ jresult = json.loads(response.content)
+ self.assertTrue(jresult['result'])
+
+ qgs_feature = editing_layer.qgis_layer.getFeature(int(newid))
+
+ self.assertTrue(f'Viewer user group1' in qgs_feature.attribute('insert_log'))
+ self.assertTrue(f'Viewer user group1' in qgs_feature.attribute('update_log'))
+
+ self.client.logout()
+
def test_editing_provider_default_value(self):
""" Test Editing API mode: MODE_COMMIT with fields having provider default values """
diff --git a/g3w-admin/editing/tests/test_views.py b/g3w-admin/editing/tests/test_views.py
index 6c21cb1e8..a4b41153a 100644
--- a/g3w-admin/editing/tests/test_views.py
+++ b/g3w-admin/editing/tests/test_views.py
@@ -593,7 +593,9 @@ def test_editing_layer_active_logging_fields(self):
data = {
'active': 'on',
'add_user_field': 'insert_log',
- 'edit_user_field': 'insert_log'
+ 'edit_user_field': 'insert_log',
+ 'add_user_group_field': 'insert_log',
+ 'edit_user_group_field': 'insert_log'
}
res = self.client.post(url, data)
@@ -605,11 +607,15 @@ def test_editing_layer_active_logging_fields(self):
self.assertTrue(len(editing_layers) == 1)
self.assertFalse(editing_layers[0].add_user_field)
self.assertFalse(editing_layers[0].edit_user_field)
+ self.assertFalse(editing_layers[0].add_user_group_field)
+ self.assertFalse(editing_layers[0].edit_user_group_field)
data = {
'active': 'on',
'add_user_field': 'insert_log',
- 'edit_user_field': 'update_log'
+ 'edit_user_field': 'update_log',
+ 'add_user_group_field': '',
+ 'edit_user_group_field': ''
}
res = self.client.post(url, data)
@@ -621,9 +627,13 @@ def test_editing_layer_active_logging_fields(self):
self.assertTrue(len(editing_layers) == 1)
self.assertEqual(editing_layers[0].add_user_field, 'insert_log')
self.assertEqual(editing_layers[0].edit_user_field, 'update_log')
+ self.assertFalse(editing_layers[0].add_user_group_field)
+ self.assertFalse(editing_layers[0].edit_user_group_field)
data = {
'active': 'on',
+ 'add_user_group_field': 'insert_log',
+ 'edit_user_group_field': 'update_log'
}
res = self.client.post(url, data)
@@ -635,6 +645,29 @@ def test_editing_layer_active_logging_fields(self):
self.assertTrue(len(editing_layers) == 1)
self.assertFalse(editing_layers[0].add_user_field)
self.assertFalse(editing_layers[0].edit_user_field)
+ self.assertEqual(editing_layers[0].add_user_group_field, 'insert_log')
+ self.assertEqual(editing_layers[0].edit_user_group_field, 'update_log')
+
+
+ data = {
+ 'active': 'on',
+ 'add_user_field': '',
+ 'edit_user_field': '',
+ 'add_user_group_field': '',
+ 'edit_user_group_field': ''
+ }
+
+ res = self.client.post(url, data)
+
+ # redirect on ok results
+ self.assertEqual(res.status_code, 302)
+
+ editing_layers = G3WEditingLayer.objects.filter(layer_id=editing_layer.pk)
+ self.assertTrue(len(editing_layers) == 1)
+ self.assertFalse(editing_layers[0].add_user_field)
+ self.assertFalse(editing_layers[0].edit_user_field)
+ self.assertFalse(editing_layers[0].add_user_group_field)
+ self.assertFalse(editing_layers[0].edit_user_group_field)
diff --git a/g3w-admin/editing/views.py b/g3w-admin/editing/views.py
index facfd2178..6d96fc606 100644
--- a/g3w-admin/editing/views.py
+++ b/g3w-admin/editing/views.py
@@ -180,6 +180,8 @@ def get_form_kwargs(self):
kwargs['initial']['scale'] = self.activated.scale
kwargs['initial']['add_user_field'] = self.activated.add_user_field
kwargs['initial']['edit_user_field'] = self.activated.edit_user_field
+ kwargs['initial']['add_user_group_field'] = self.activated.add_user_group_field
+ kwargs['initial']['edit_user_group_field'] = self.activated.edit_user_group_field
except:
self.activated = None
kwargs['initial']['active'] = False
@@ -275,6 +277,8 @@ def form_valid(self, form):
visible = form.cleaned_data['visible']
add_user_field = form.cleaned_data['add_user_field']
edit_user_field = form.cleaned_data['edit_user_field']
+ add_user_group_field = form.cleaned_data['add_user_group_field']
+ edit_user_group_field = form.cleaned_data['edit_user_group_field']
if form.cleaned_data['active']:
if not self.activated:
@@ -283,12 +287,17 @@ def form_valid(self, form):
scale=scale,
visible=visible,
add_user_field=add_user_field,
- edit_user_field=edit_user_field)
+ edit_user_field=edit_user_field,
+ add_user_group_field=add_user_group_field,
+ edit_user_group_field=edit_user_group_field
+ )
else:
self.activated.visible = visible
self.activated.scale = scale
self.activated.add_user_field = add_user_field
self.activated.edit_user_field = edit_user_field
+ self.activated.add_user_group_field = add_user_group_field
+ self.activated.edit_user_group_field = edit_user_group_field
self.activated.save()
else:
if self.activated:
@@ -431,6 +440,8 @@ def form_valid(self, form):
add_user_field = self.request.POST.get(f'add_user_field_{layer_pk}', None)
edit_user_field = self.request.POST.get(f'edit_user_field_{layer_pk}', None)
+ add_user_group_field = self.request.POST.get(f'add_user_group_field_{layer_pk}', None)
+ edit_user_group_field = self.request.POST.get(f'edit_user_group_field_{layer_pk}', None)
if form.cleaned_data['active']:
@@ -439,6 +450,8 @@ def form_valid(self, form):
layer_id=layer_pk,
edit_user_field=edit_user_field,
add_user_field=add_user_field,
+ edit_user_group_field=edit_user_group_field,
+ add_user_group_field=add_user_group_field,
scale=scale,
visible=visible)
else:
@@ -446,6 +459,8 @@ def form_valid(self, form):
activated[layer_pk].scale = scale
activated[layer_pk].add_user_field = add_user_field
activated[layer_pk].edit_user_field = edit_user_field
+ activated[layer_pk].add_user_group_field = add_user_group_field
+ activated[layer_pk].edit_user_group_field = edit_user_group_field
activated[layer_pk].save()
else:
if layer_pk in activated.keys():
diff --git a/g3w-admin/qdjango/templates/qdjango/ajax/project_detail.html b/g3w-admin/qdjango/templates/qdjango/ajax/project_detail.html
index d277d4a19..c95e6597d 100644
--- a/g3w-admin/qdjango/templates/qdjango/ajax/project_detail.html
+++ b/g3w-admin/qdjango/templates/qdjango/ajax/project_detail.html
@@ -101,6 +101,8 @@