Skip to content

Commit

Permalink
[ISSUE #6551] Minor review of the current advanced resource workflow …
Browse files Browse the repository at this point in the history
…implementation… (#6552)

* Minor review of the current advanced resource workflow implementation #6551

* Fix tests on Travis

* Fix logical errors on approval workflow

* Fix tests on Travis

* Advanced workflow: remove change_permissions to the owner if not a manager

(cherry picked from commit 9a1552a)

* Advanced workflow: remove change_permissions to the owner if not a manager

(cherry picked from commit f23096c)

* Advanced workflow: remove change_permissions to the owner if not a manager

(cherry picked from commit bfe51a7)

* Advanced workflow: remove change_permissions to the owner if not a manager

(cherry picked from commit d9ec566)

* Advanced workflow: filter actions stream returned to the users accordingly to their perms

(cherry picked from commit 7f51346)

* Advanced workflow: filter actions stream returned to the users accordingly to their perms

* Add new settings from django-allauth 0.43.0

* Code styling alerts: remove unnecessary pass

(cherry picked from commit 0676f6e)

* Refreshing static libs

(cherry picked from commit f27d0df)

* Refreshing static libs

(cherry picked from commit 5b166bc)

* Advanced Workflow: Make sure the APIs counters are coherent with the visible resources

(cherry picked from commit 1855d74)

* Advanced Workflow: fix "request editing" action when published

(cherry picked from commit 1041b12)

* Advanced Workflow: fix "request editing" action when published -> send messages to group managers too

(cherry picked from commit 5c93ef3)

* Fix test on travis

* Merge branch 'master' into adv_workflow_improvements
  • Loading branch information
Alessio Fabiani authored Oct 25, 2020
1 parent b664218 commit 7de3a3c
Show file tree
Hide file tree
Showing 30 changed files with 441 additions and 245 deletions.
15 changes: 8 additions & 7 deletions geonode/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,8 @@ def dehydrate_member_count(self, bundle):
def dehydrate(self, bundle):
"""Provide additional resource counts"""
request = bundle.request
_user = request.user
counts = _get_resource_counts(
_user,
request,
resourcebase_filter_kwargs={
'group__groupprofile__categories': bundle.obj
}
Expand Down Expand Up @@ -408,11 +407,11 @@ class Meta:
def dehydrate(self, bundle):
"""Provide additional resource counts"""
request = bundle.request
_user = request.user
counts = _get_resource_counts(
_user,
request,
resourcebase_filter_kwargs={'group': bundle.obj}
)

bundle.data.update(resource_counts=counts)
return bundle

Expand Down Expand Up @@ -835,15 +834,15 @@ class StyleResource(GeoserverStyleResource):
pass


def _get_resource_counts(user, resourcebase_filter_kwargs):
def _get_resource_counts(request, resourcebase_filter_kwargs):
"""Return a dict with counts of resources of various types
The ``resourcebase_filter_kwargs`` argument should be a dict with a suitable
queryset filter that can be applied to select only the relevant
``ResourceBase`` objects to use when retrieving counts. For example::
_get_resource_counts(
user,
request,
{
'group__slug': 'my-group',
}
Expand All @@ -855,10 +854,12 @@ def _get_resource_counts(user, resourcebase_filter_kwargs):
"""
resources = get_visible_resources(
ResourceBase.objects.filter(**resourcebase_filter_kwargs),
user,
request.user,
request=request,
admin_approval_required=settings.ADMIN_MODERATE_UPLOADS,
unpublished_not_visible=settings.RESOURCE_PUBLISHING,
private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES)

values = resources.values(
'polymorphic_ctype__model',
'is_approved',
Expand Down
4 changes: 2 additions & 2 deletions geonode/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,15 @@ def test_layer_get_list_layer_private_to_one_user(self):
# with resource publishing
with self.settings(RESOURCE_PUBLISHING=True):
resp = self.api_client.get(self.list_url)
self.assertEqual(len(self.deserialize(resp)['objects']), 8)
self.assertEqual(len(self.deserialize(resp)['objects']), 0)

self.api_client.client.login(username='bobby', password='bob')
resp = self.api_client.get(self.list_url)
self.assertEqual(len(self.deserialize(resp)['objects']), 2)

self.api_client.client.login(username=self.user, password=self.passwd)
resp = self.api_client.get(self.list_url)
self.assertEqual(len(self.deserialize(resp)['objects']), 8)
self.assertEqual(len(self.deserialize(resp)['objects']), 0)

def test_layer_get_detail_unauth_layer_not_public(self):
"""
Expand Down
8 changes: 8 additions & 0 deletions geonode/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,10 @@ def save(self, notify=False, *args, **kwargs):
if settings.ADMIN_MODERATE_UPLOADS:
if self.is_approved and not self.is_published and \
self.__is_approved != self.is_approved:
# Set "approved" workflow permissions
self.set_workflow_perms(approved=True)

# Send "approved" notification
notice_type_label = '%s_approved' % self.class_name.lower()
recipients = get_notification_recipients(notice_type_label)
send_notification(recipients, notice_type_label, {'resource': self})
Expand All @@ -888,6 +892,10 @@ def save(self, notify=False, *args, **kwargs):
if not _notification_sent and settings.RESOURCE_PUBLISHING:
if self.is_approved and self.is_published and \
self.__is_published != self.is_published:
# Set "published" workflow permissions
self.set_workflow_perms(published=True)

# Send "published" notification
notice_type_label = '%s_published' % self.class_name.lower()
recipients = get_notification_recipients(notice_type_label)
send_notification(recipients, notice_type_label, {'resource': self})
Expand Down
29 changes: 17 additions & 12 deletions geonode/base/templatetags/base_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
#########################################################################

from django import template

from pinax.ratings.models import Rating
from django.db.models import Q
from django.conf import settings
from django.db.models import Count
from django.utils.translation import ugettext
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import get_user_model
from django.db.models import Count
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType

from pinax.ratings.models import Rating
from guardian.shortcuts import get_objects_for_user

from geonode.base.models import ResourceBase
Expand All @@ -45,11 +45,11 @@
register = template.Library()

FACETS = {
'raster': 'Raster Layer',
'vector': 'Vector Layer',
'vector_time': 'Vector Temporal Serie',
'remote': 'Remote Layer',
'wms': 'WMS Cascade Layer'
'raster': _('Raster Layer'),
'vector': _('Vector Layer'),
'vector_time': _('Vector Temporal Serie'),
'remote': _('Remote Layer'),
'wms': _('WMS Cascade Layer')
}


Expand Down Expand Up @@ -344,8 +344,13 @@ def get_visibile_resources(user):
@register.simple_tag
def display_edit_request_button(resource, user, perms):
def _has_owner_his_permissions():
return (set(resource.BASE_PERMISSIONS.get('owner') + resource.BASE_PERMISSIONS.get('write')) - set(
perms)) == set()
_owner_set = set(resource.BASE_PERMISSIONS.get('owner') +
resource.BASE_PERMISSIONS.get('read') +
resource.BASE_PERMISSIONS.get('write') +
resource.BASE_PERMISSIONS.get('download')) - \
set(perms)
return _owner_set == set() or \
_owner_set == set(['change_resourcebase_permissions', 'publish_resourcebase'])

if not _has_owner_his_permissions() and resource.owner.pk == user.pk:
return True
Expand Down
4 changes: 2 additions & 2 deletions geonode/base/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,12 +775,12 @@ def test_get_concrete_resource(self):
@override_settings(ADMIN_MODERATE_UPLOADS=True)
def test_msg_recipients_admin_mode(self):
users_count = 1
self.assertEqual(users_count, OwnerRightsRequestViewUtils.get_message_recipients().count())
self.assertEqual(users_count, OwnerRightsRequestViewUtils.get_message_recipients(self.user).count())

@override_settings(ADMIN_MODERATE_UPLOADS=False)
def test_msg_recipients_workflow_off(self):
users_count = 0
self.assertEqual(users_count, OwnerRightsRequestViewUtils.get_message_recipients().count())
self.assertEqual(users_count, OwnerRightsRequestViewUtils.get_message_recipients(self.user).count())


class TestGetVisibleResource(TestCase):
Expand Down
36 changes: 31 additions & 5 deletions geonode/base/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,28 @@ def configuration_session_cache(session):
class OwnerRightsRequestViewUtils:

@staticmethod
def get_message_recipients():
def get_message_recipients(owner):
User = get_user_model()
allowed_users = User.objects.none()
if OwnerRightsRequestViewUtils.is_admin_publish_mode():
allowed_users |= User.objects.filter(is_superuser=True)
allowed_users |= User.objects.filter(is_superuser=True).exclude(pk=owner.pk)
try:
from geonode.groups.models import GroupProfile
groups = owner.groups.all()
obj_group_managers = []
for group in groups:
try:
group_profile = GroupProfile.objects.get(slug=group.name)
managers = group_profile.get_managers()
for manager in managers:
if manager not in obj_group_managers and not manager.is_superuser:
obj_group_managers.append(manager)
except GroupProfile.DoesNotExist:
pass
allowed_users |= User.objects.filter(id__in=[_u.id for _u in obj_group_managers])
except Exception:
pass

return allowed_users

@staticmethod
Expand Down Expand Up @@ -180,14 +197,23 @@ def _disable_owner_write_permissions(self):
remove_perm(perm, self.resource.owner, self.resource)

for perm in self.resource.BASE_PERMISSIONS.get('read') + self.resource.BASE_PERMISSIONS.get('download'):
assign_perm(perm, self.resource.owner, self.resource.get_self_resource())
if not settings.RESOURCE_PUBLISHING and not settings.ADMIN_MODERATE_UPLOADS:
assign_perm(perm, self.resource.owner, self.resource.get_self_resource())
elif perm not in ['change_resourcebase_permissions', 'publish_resourcebase']:
assign_perm(perm, self.resource.owner, self.resource.get_self_resource())

def _restore_owner_permissions(self):

for perm_list in self.resource.BASE_PERMISSIONS.values():
for perm in perm_list:
assign_perm(perm, self.resource.owner, self.resource.get_self_resource())
if not settings.RESOURCE_PUBLISHING and not settings.ADMIN_MODERATE_UPLOADS:
assign_perm(perm, self.resource.owner, self.resource.get_self_resource())
elif perm not in ['change_resourcebase_permissions', 'publish_resourcebase']:
assign_perm(perm, self.resource.owner, self.resource.get_self_resource())

for perm_list in self.resource.PERMISSIONS.values():
for perm in perm_list:
assign_perm(perm, self.resource.owner, self.resource)
if not settings.RESOURCE_PUBLISHING and not settings.ADMIN_MODERATE_UPLOADS:
assign_perm(perm, self.resource.owner, self.resource)
elif perm not in ['change_resourcebase_permissions', 'publish_resourcebase']:
assign_perm(perm, self.resource.owner, self.resource)
8 changes: 4 additions & 4 deletions geonode/base/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,17 +248,17 @@ def post(self, request, *args, **kwargs):
if form.is_valid():
reason = form.cleaned_data['reason']
notice_type_label = 'request_resource_edit'
recipients = OwnerRightsRequestViewUtils.get_message_recipients()
recipients = OwnerRightsRequestViewUtils.get_message_recipients(self.resource.owner)

Message.objects.new_message(
from_user=request.user,
to_users=recipients,
subject=_('System message: A request to modify resource'),
content=_('The resource owner has requested to modify the resource') + '.'
content=_('The resource owner has requested to modify the resource') + '.\n'
' ' +
_('Resource title') + ': ' + self.resource.title + '.'
_('Resource title') + ': ' + self.resource.title + '.\n'
' ' +
_('Reason for the request') + ': "' + reason + '".' +
_('Reason for the request') + ': "' + reason + '".\n' +
' ' +
_('To allow the change, set the resource to not "Approved" under the metadata settings' +
'and write message to the owner to notify him') + '.'
Expand Down
7 changes: 3 additions & 4 deletions geonode/documents/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,10 +549,6 @@ def document_metadata(

if settings.ADMIN_MODERATE_UPLOADS:
if not request.user.is_superuser:
if settings.RESOURCE_PUBLISHING:
document_form.fields['is_published'].widget.attrs.update(
{'disabled': 'true'})

can_change_metadata = request.user.has_perm(
'change_resourcebase_metadata',
document.get_self_resource())
Expand All @@ -561,6 +557,9 @@ def document_metadata(
except Exception:
is_manager = False
if not is_manager or not can_change_metadata:
if settings.RESOURCE_PUBLISHING:
document_form.fields['is_published'].widget.attrs.update(
{'disabled': 'true'})
document_form.fields['is_approved'].widget.attrs.update(
{'disabled': 'true'})

Expand Down
13 changes: 10 additions & 3 deletions geonode/geoserver/createlayer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################

import requests
import json
import uuid
import logging
import json
import requests

from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.gis.geos import Polygon
from django.template.defaultfilters import slugify
Expand Down Expand Up @@ -77,6 +77,13 @@ def create_gn_layer(workspace, datastore, name, title, owner_name):
bbox_polygon=Polygon.from_bbox(BBOX),
data_quality_statement=DATA_QUALITY_MESSAGE,
)

if settings.ADMIN_MODERATE_UPLOADS:
layer.is_approved = False
if settings.RESOURCE_PUBLISHING:
layer.is_published = False

layer.save()
return layer


Expand Down
2 changes: 1 addition & 1 deletion geonode/geoserver/createlayer/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def layer_create(request, template='createlayer/layer_create.html'):
attributes = form.cleaned_data['attributes']
permissions = form.cleaned_data["permissions"]
layer = create_layer(name, title, request.user.username, geometry_type, attributes)
layer.set_permissions(json.loads(permissions))
layer.set_permissions(json.loads(permissions), created=True)
return redirect(layer)
except Exception as e:
error = '%s (%s)' % (e, type(e))
Expand Down
Loading

0 comments on commit 7de3a3c

Please sign in to comment.