diff --git a/docs/reference/developers/settings.txt b/docs/reference/developers/settings.txt index bdb87addf58..cb75353f4be 100644 --- a/docs/reference/developers/settings.txt +++ b/docs/reference/developers/settings.txt @@ -155,9 +155,9 @@ Specific settings for map API providers (if they are not set those base maps wil * BING_API_KEY set this variable to your BING Map Key value -LAYER_PREVIEW_LIBRARY ---------------------- -Default: ``"leaflet"`` +GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY +------------------------------------ +Default: ``"geoext"`` The library to use for display preview images of layers. The library choices are: diff --git a/docs/tutorials/advanced/geonode_settings/settings.txt b/docs/tutorials/advanced/geonode_settings/settings.txt index 66f46d7ddff..ba7be0c6914 100644 --- a/docs/tutorials/advanced/geonode_settings/settings.txt +++ b/docs/tutorials/advanced/geonode_settings/settings.txt @@ -151,9 +151,9 @@ Default:: A list of dictionaries that specify the default map layers. -LAYER_PREVIEW_LIBRARY ---------------------- -Default: ``"leaflet"`` +GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY +------------------------------------ +Default: ``"geoext"`` The library to use for display preview images of layers. The library choices are: diff --git a/docs/tutorials/install_and_admin/setup_on_centos/install_geonode.txt b/docs/tutorials/install_and_admin/setup_on_centos/install_geonode.txt index f2ae2debb08..57bdbb272de 100644 --- a/docs/tutorials/install_and_admin/setup_on_centos/install_geonode.txt +++ b/docs/tutorials/install_and_admin/setup_on_centos/install_geonode.txt @@ -232,7 +232,7 @@ The resulting configuration file should look like this::: } # Default preview library - #LAYER_PREVIEW_LIBRARY = 'geoext' + # GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY = 'geoext' .. _geonode_install_initialization: diff --git a/geonode/api/api.py b/geonode/api/api.py index 0a693ad7a61..c87070560bc 100644 --- a/geonode/api/api.py +++ b/geonode/api/api.py @@ -47,12 +47,10 @@ from geonode.base.models import Region from geonode.base.models import HierarchicalKeyword from geonode.base.models import ThesaurusKeywordLabel - from geonode.layers.models import Layer, Style from geonode.maps.models import Map from geonode.documents.models import Document from geonode.groups.models import GroupProfile, GroupCategory -from django.contrib.auth.models import Group from django.core.serializers.json import DjangoJSONEncoder from tastypie.serializers import Serializer from tastypie import fields @@ -61,6 +59,7 @@ from tastypie.utils import trailing_slash from geonode.utils import check_ogc_backend +from geonode.security.utils import get_visible_resources FILTER_TYPES = { 'layer': Layer, @@ -80,8 +79,13 @@ def get_resources_counts(self, options): options['user'], 'base.view_resourcebase' ) - if settings.RESOURCE_PUBLISHING: - resources = resources.filter(Q(is_published=True) | Q(owner__username__iexact=str(options['user']))) + + resources = get_visible_resources( + resources, + options['user'], + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) if options['title_filter']: resources = resources.filter(title__icontains=options['title_filter']) @@ -248,95 +252,12 @@ def dehydrate_layers_count(self, bundle): filter_set = bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id')) if not settings.SKIP_PERMS_FILTER: - is_admin = False - is_manager = False - if request.user: - is_admin = request.user.is_superuser if request.user else False - try: - is_manager = request.user.groupmember_set.all().filter(role='manager').exists() - except: - is_manager = False - - # Get the list of objects the user has access to - anonymous_group = None - public_groups = GroupProfile.objects.exclude(access="private").values('group') - groups = [] - group_list_all = [] - manager_groups = [] - try: - group_list_all = request.user.group_list_all().values('group') - except: - pass - try: - manager_groups = Group.objects.filter( - name__in=request.user.groupmember_set.filter(role="manager").values_list("group__slug", flat=True)) - except: - pass - try: - anonymous_group = Group.objects.get(name='anonymous') - if anonymous_group and anonymous_group not in groups: - groups.append(anonymous_group) - except: - pass - - if settings.ADMIN_MODERATE_UPLOADS: - if not is_admin: - if is_manager: - filter_set = filter_set.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - filter_set = filter_set.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - filter_set = filter_set.filter(Q(is_published=True)) - - if settings.RESOURCE_PUBLISHING: - if not is_admin: - if is_manager: - filter_set = filter_set.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - filter_set = filter_set.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - filter_set = filter_set.filter(Q(is_published=True)) - - if settings.GROUP_PRIVATE_RESOURCES: - if is_admin: - filter_set = filter_set - elif request.user: - filter_set = filter_set.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=public_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - if anonymous_group: - filter_set = filter_set.filter( - Q(group__isnull=True) | - Q(group__in=public_groups) | - Q(group=anonymous_group)) - else: - filter_set = filter_set.filter( - Q(group__isnull=True) | - Q(group__in=public_groups)) + filter_set = get_visible_resources( + filter_set, + request.user if request else None, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) return filter_set.distinct().count() diff --git a/geonode/api/resourcebase_api.py b/geonode/api/resourcebase_api.py index d28cf3facf9..77faf3e6dbd 100644 --- a/geonode/api/resourcebase_api.py +++ b/geonode/api/resourcebase_api.py @@ -41,7 +41,6 @@ from django.core.paginator import Paginator, InvalidPage from django.http import Http404 from django.core.exceptions import ObjectDoesNotExist -from django.contrib.auth.models import Group from django.forms.models import model_to_dict from tastypie.utils.mime import build_content_type @@ -55,6 +54,7 @@ from geonode.people.models import Profile from geonode.groups.models import GroupProfile from geonode.utils import check_ogc_backend +from geonode.security.utils import get_visible_resources from .authorization import GeoNodeAuthorization, GeonodeApiKeyAuthentication @@ -203,123 +203,21 @@ def apply_filters(self, request, applicable_filters): return filtered def filter_published(self, queryset, request): - is_admin = False - is_manager = False - if request.user: - is_admin = request.user.is_superuser if request.user else False - try: - is_manager = request.user.groupmember_set.all().filter(role='manager').exists() - except: - is_manager = False - - # Get the list of objects the user has access to - anonymous_group = None - public_groups = GroupProfile.objects.exclude(access="private").values('group') - groups = [] - group_list_all = [] - manager_groups = [] - try: - group_list_all = request.user.group_list_all().values('group') - except: - pass - try: - manager_groups = Group.objects.filter( - name__in=request.user.groupmember_set.filter(role="manager").values_list("group__slug", flat=True)) - except: - pass - try: - anonymous_group = Group.objects.get(name='anonymous') - if anonymous_group and anonymous_group not in groups: - groups.append(anonymous_group) - except: - pass - - filtered = queryset - if settings.ADMIN_MODERATE_UPLOADS: - if not is_admin: - if is_manager: - filtered = filtered.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - filtered = filtered.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - filtered = filtered.filter(Q(is_published=True)) - - if settings.RESOURCE_PUBLISHING: - if not is_admin: - if is_manager: - filtered = filtered.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - filtered = filtered.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - filtered = filtered.filter(Q(is_published=True)) + filter_set = get_visible_resources( + queryset, + request.user if request else None, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING) - return filtered + return filter_set def filter_group(self, queryset, request): - is_admin = False - if request.user: - is_admin = request.user.is_superuser if request.user else False + filter_set = get_visible_resources( + queryset, + request.user if request else None, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) - try: - anonymous_group = Group.objects.get(name='anonymous') - except BaseException: - anonymous_group = None - - public_groups = GroupProfile.objects.exclude(access="private").values('group') - if is_admin: - filtered = queryset - elif request.user: - groups = request.user.groups.all() - group_list_all = [] - try: - group_list_all = request.user.group_list_all().values('group') - except: - pass - if anonymous_group: - filtered = queryset.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(group=anonymous_group) | - Q(owner__username__iexact=str(request.user))) - else: - filtered = queryset.filter( - Q(group__isnull=True) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(group__in=groups) | - Q(owner__username__iexact=str(request.user))) - else: - if anonymous_group: - filtered = queryset.filter( - Q(group__isnull=True) | - Q(group__in=public_groups) | - Q(group=anonymous_group)) - else: - filtered = queryset.filter( - Q(group__isnull=True) | - Q(group__in=public_groups)) - return filtered + return filter_set def filter_h_keywords(self, queryset, keywords): filtered = queryset @@ -540,98 +438,16 @@ def get_search(self, request, **kwargs): sqs = self.build_haystack_filters(request.GET) if not settings.SKIP_PERMS_FILTER: - is_admin = False - is_manager = False - if request.user: - is_admin = request.user.is_superuser if request.user else False - try: - is_manager = request.user.groupmember_set.all().filter(role='manager').exists() - except: - is_manager = False filter_set = get_objects_for_user( request.user, 'base.view_resourcebase') - # Get the list of objects the user has access to - anonymous_group = None - public_groups = GroupProfile.objects.exclude(access="private").values('group') - groups = [] - group_list_all = [] - manager_groups = [] - try: - group_list_all = request.user.group_list_all().values('group') - except: - pass - try: - manager_groups = Group.objects.filter( - name__in=request.user.groupmember_set.filter(role="manager").values_list("group__slug", flat=True)) - except: - pass - try: - anonymous_group = Group.objects.get(name='anonymous') - if anonymous_group and anonymous_group not in groups: - groups.append(anonymous_group) - except: - pass - - if settings.ADMIN_MODERATE_UPLOADS: - if not is_admin: - if is_manager: - filter_set = filter_set.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - filter_set = filter_set.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - filter_set = filter_set.filter(Q(is_published=True)) - - if settings.RESOURCE_PUBLISHING: - if not is_admin: - if is_manager: - filter_set = filter_set.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - filter_set = filter_set.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - filter_set = filter_set.filter(Q(is_published=True)) - - if settings.GROUP_PRIVATE_RESOURCES: - if is_admin: - filter_set = filter_set - elif request.user: - filter_set = filter_set.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=public_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - if anonymous_group: - filter_set = filter_set.filter( - Q(group__isnull=True) | - Q(group__in=public_groups) | - Q(group=anonymous_group)) - else: - filter_set = filter_set.filter( - Q(group__isnull=True) | - Q(group__in=public_groups)) + filter_set = get_visible_resources( + filter_set, + request.user if request else None, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) filter_set_ids = filter_set.values_list('id') # Do the query using the filterset and the query term. Facet the diff --git a/geonode/base/autocomplete_light_registry.py b/geonode/base/autocomplete_light_registry.py index 95ae0318ce7..4e29ca11257 100644 --- a/geonode/base/autocomplete_light_registry.py +++ b/geonode/base/autocomplete_light_registry.py @@ -24,8 +24,7 @@ from guardian.shortcuts import get_objects_for_user from django.conf import settings from django.db.models import Q -from django.contrib.auth.models import Group -from geonode.groups.models import GroupProfile +from geonode.security.utils import get_visible_resources from models import ResourceBase, Region, HierarchicalKeyword, ThesaurusKeywordLabel @@ -41,92 +40,12 @@ def choices_for_request(self): 'base.view_resourcebase') self.choices = self.choices.filter(id__in=permitted) - is_admin = False - is_manager = False - if request.user: - is_admin = request.user.is_superuser if request.user else False - try: - is_manager = request.user.groupmember_set.all().filter(role='manager').exists() - except: - is_manager = False - - # Get the list of objects the user has access to - anonymous_group = None - public_groups = GroupProfile.objects.exclude(access="private").values('group') - groups = [] - group_list_all = [] - manager_groups = [] - try: - group_list_all = request.user.group_list_all().values('group') - except: - pass - try: - manager_groups = Group.objects.filter( - name__in=request.user.groupmember_set.filter(role="manager").values_list("group__slug", flat=True)) - except: - pass - try: - anonymous_group = Group.objects.get(name='anonymous') - if anonymous_group and anonymous_group not in groups: - groups.append(anonymous_group) - except: - pass - - if settings.ADMIN_MODERATE_UPLOADS: - if not is_admin: - if is_manager: - self.choices = self.choices.filter( - Q(is_published=True) | - Q(group__in=manager_groups) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - self.choices = self.choices.filter( - Q(is_published=True) | - Q(owner__username__iexact=str(request.user))) - else: - self.choices = self.choices.filter(Q(is_published=True)) - - if settings.RESOURCE_PUBLISHING: - if not is_admin: - if is_manager: - self.choices = self.choices.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - self.choices = self.choices.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - self.choices = self.choices.filter(Q(is_published=True)) - - if settings.GROUP_PRIVATE_RESOURCES: - public_groups = GroupProfile.objects.exclude(access="private").values('group') - if is_admin: - self.choices = self.choices - elif request.user: - self.choices = self.choices.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=public_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - if anonymous_group: - self.choices = self.choices.filter( - Q(group__isnull=True) | - Q(group__in=public_groups) | - Q(group=anonymous_group)) - else: - self.choices = self.choices.filter( - Q(group__isnull=True) | - Q(group__in=public_groups)) + self.choices = get_visible_resources( + self.choices, + request.user if request else None, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) return super(ResourceBaseAutocomplete, self).choices_for_request() diff --git a/geonode/base/management/commands/fixgeofencerules.py b/geonode/base/management/commands/fixgeofencerules.py index 3b5e838ebc6..96f67a4aa60 100644 --- a/geonode/base/management/commands/fixgeofencerules.py +++ b/geonode/base/management/commands/fixgeofencerules.py @@ -24,7 +24,7 @@ from geonode.people.models import Profile from geonode.layers.models import Layer -from geonode.security import models +from geonode.security import utils class Command(BaseCommand): @@ -42,7 +42,7 @@ def handle(self, *args, **options): for index, layer in enumerate(layers): print "[%s / %s] Setting default permissions to Layer [%s] ..." % ((index + 1), len(layers), layer.name) try: - models.set_geofence_all(layer) + utils.set_geofence_all(layer) except: print "[ERROR] Layer [%s] couldn't be updated" % (layer.name) @@ -52,13 +52,13 @@ def handle(self, *args, **options): print "[%s / %s] Setting owner permissions to Layer [%s] ..." \ % ((index + 1), len(protected_layers), layer.name) try: - perms = models.get_users_with_perms(layer) + perms = utils.get_users_with_perms(layer) for profile in perms.keys(): print " - [%s / %s]" % (str(profile), layer.name) geofence_user = str(profile) if "AnonymousUser" in geofence_user: geofence_user = None - models.set_geofence_owner( + utils.set_geofence_owner( layer, geofence_user, view_perms=True, download_perms=True diff --git a/geonode/base/management/commands/set_all_layers_public.py b/geonode/base/management/commands/set_all_layers_public.py index ba8a8eadb4c..b089d3a45b4 100644 --- a/geonode/base/management/commands/set_all_layers_public.py +++ b/geonode/base/management/commands/set_all_layers_public.py @@ -21,7 +21,7 @@ from django.conf import settings from django.core.management.base import BaseCommand from geonode.layers.models import Layer -from geonode.security.models import set_geofence_all +from geonode.security.utils import set_geofence_all class Command(BaseCommand): diff --git a/geonode/base/templatetags/base_tags.py b/geonode/base/templatetags/base_tags.py index 2f3147dceab..4e0c373cbb2 100644 --- a/geonode/base/templatetags/base_tags.py +++ b/geonode/base/templatetags/base_tags.py @@ -24,7 +24,6 @@ from django.db.models import Q from django.contrib.contenttypes.models import ContentType from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group from django.db.models import Count from django.conf import settings @@ -35,6 +34,7 @@ from geonode.documents.models import Document from geonode.groups.models import GroupProfile from geonode.base.models import HierarchicalKeyword +from geonode.security.utils import get_visible_resources register = template.Library() @@ -56,15 +56,6 @@ def num_ratings(obj): @register.assignment_tag(takes_context=True) def facets(context): request = context['request'] - is_admin = False - is_manager = False - if request.user: - is_admin = request.user.is_superuser if request.user else False - try: - is_manager = request.user.groupmember_set.all().filter(role='manager').exists() - except: - is_manager = False - title_filter = request.GET.get('title__icontains', '') extent_filter = request.GET.get('extent', None) keywords_filter = request.GET.getlist('keywords__slug__in', None) @@ -101,86 +92,12 @@ def facets(context): if date_range_filter: documents = documents.filter(date__range=date_range_filter.split(',')) - # Get the list of objects the user has access to - anonymous_group = None - public_groups = GroupProfile.objects.exclude(access="private").values('group') - groups = [] - group_list_all = [] - manager_groups = [] - try: - group_list_all = request.user.group_list_all().values('group') - except: - pass - try: - manager_groups = Group.objects.filter( - name__in=request.user.groupmember_set.filter(role="manager").values_list("group__slug", flat=True)) - except: - pass - try: - anonymous_group = Group.objects.get(name='anonymous') - if anonymous_group and anonymous_group not in groups: - groups.append(anonymous_group) - except: - pass - - if settings.ADMIN_MODERATE_UPLOADS: - if not is_admin: - if is_manager: - documents = documents.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - documents = documents.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - documents = documents.filter(Q(is_published=True)) - - if settings.RESOURCE_PUBLISHING: - if not is_admin: - if is_manager: - documents = documents.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - documents = documents.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - documents = documents.filter(Q(is_published=True)) - - if settings.GROUP_PRIVATE_RESOURCES: - if is_admin: - pass - elif request.user: - documents = documents.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=public_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - if anonymous_group: - documents = documents.filter( - Q(group__isnull=True) | - Q(group__in=public_groups) | - Q(group=anonymous_group)) - else: - documents = documents.filter( - Q(group__isnull=True) | - Q(group__in=public_groups)) + documents = get_visible_resources( + documents, + request.user if request else None, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) if keywords_filter: treeqs = HierarchicalKeyword.objects.none() @@ -223,86 +140,12 @@ def facets(context): if date_range_filter: layers = layers.filter(date__range=date_range_filter.split(',')) - # Get the list of objects the user has access to - anonymous_group = None - public_groups = GroupProfile.objects.exclude(access="private").values('group') - groups = [] - group_list_all = [] - manager_groups = [] - try: - group_list_all = request.user.group_list_all().values('group') - except: - pass - try: - manager_groups = Group.objects.filter( - name__in=request.user.groupmember_set.filter(role="manager").values_list("group__slug", flat=True)) - except: - pass - try: - anonymous_group = Group.objects.get(name='anonymous') - if anonymous_group and anonymous_group not in groups: - groups.append(anonymous_group) - except: - pass - - if settings.ADMIN_MODERATE_UPLOADS: - if not is_admin: - if is_manager: - layers = layers.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - layers = layers.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - layers = layers.filter(Q(is_published=True)) - - if settings.RESOURCE_PUBLISHING: - if not is_admin: - if is_manager: - layers = layers.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - layers = layers.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - layers = layers.filter(Q(is_published=True)) - - if settings.GROUP_PRIVATE_RESOURCES: - if is_admin: - pass - elif request.user: - layers = layers.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=public_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - if anonymous_group: - layers = layers.filter( - Q(group__isnull=True) | - Q(group__in=public_groups) | - Q(group=anonymous_group)) - else: - layers = layers.filter( - Q(group__isnull=True) | - Q(group__in=public_groups)) + layers = get_visible_resources( + layers, + request.user if request else None, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) if extent_filter: bbox = extent_filter.split( @@ -375,119 +218,18 @@ def facets(context): maps = maps.filter(date__range=date_range_filter.split(',')) documents = documents.filter(date__range=date_range_filter.split(',')) - # Get the list of objects the user has access to - anonymous_group = None - public_groups = GroupProfile.objects.exclude(access="private").values('group') - groups = [] - group_list_all = [] - manager_groups = [] - try: - group_list_all = request.user.group_list_all().values('group') - except: - pass - try: - manager_groups = Group.objects.filter( - name__in=request.user.groupmember_set.filter(role="manager").values_list("group__slug", flat=True)) - except: - pass - try: - anonymous_group = Group.objects.get(name='anonymous') - if anonymous_group and anonymous_group not in groups: - groups.append(anonymous_group) - except: - pass - - if settings.ADMIN_MODERATE_UPLOADS: - if not is_admin: - if is_manager: - maps = maps.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - documents = documents.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - maps = maps.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - documents = documents.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - maps = maps.filter(Q(is_published=True)) - documents = documents.filter(Q(is_published=True)) - - if settings.RESOURCE_PUBLISHING: - if not is_admin: - if is_manager: - maps = maps.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(owner__username__iexact=str(request.user))) - documents = documents.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=group_list_all) | - Q(group__in=public_groups) | - Q(owner__username__iexact=str(request.user))) - elif request.user: - maps = maps.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - documents = documents.filter( - Q(is_published=True) | - Q(group__in=groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - maps = maps.filter(Q(is_published=True)) - documents = documents.filter(Q(is_published=True)) - - if settings.GROUP_PRIVATE_RESOURCES: - if is_admin: - pass - elif request.user: - maps = maps.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=public_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - documents = documents.filter( - Q(group__isnull=True) | - Q(group__in=groups) | - Q(group__in=manager_groups) | - Q(group__in=public_groups) | - Q(group__in=group_list_all) | - Q(owner__username__iexact=str(request.user))) - else: - if anonymous_group: - maps = maps.filter( - Q(group__isnull=True) | - Q(group=anonymous_group)) - documents = documents.filter( - Q(group__isnull=True) | - Q(group=anonymous_group)) - else: - maps = maps.filter(Q(group__isnull=True)) - documents = documents.filter(Q(group__isnull=True)) + maps = get_visible_resources( + maps, + request.user if request else None, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) + documents = get_visible_resources( + documents, + request.user if request else None, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) if extent_filter: bbox = extent_filter.split( diff --git a/geonode/client/__init__.py b/geonode/client/__init__.py new file mode 100644 index 00000000000..a0f3a990243 --- /dev/null +++ b/geonode/client/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +######################################################################### +# +# Copyright (C) 2018 OSGeo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### +from pkgutil import extend_path + + +default_app_config = "geonode.client.apps.AppConfig" +__path__ = extend_path(__path__, __name__) # noqa diff --git a/geonode/client/apps.py b/geonode/client/apps.py new file mode 100644 index 00000000000..6615a4099b4 --- /dev/null +++ b/geonode/client/apps.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +######################################################################### +# +# Copyright (C) 2018 OSGeo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### +from django.apps import AppConfig as BaseAppConfig +from django.utils.translation import ugettext_lazy as _ + + +class AppConfig(BaseAppConfig): + + name = "geonode.client" + label = "geonode_client" + verbose_name = _("GeoNode Client Library") diff --git a/geonode/client/conf.py b/geonode/client/conf.py new file mode 100644 index 00000000000..1d19edef180 --- /dev/null +++ b/geonode/client/conf.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +######################################################################### +# +# Copyright (C) 2018 OSGeo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### +import importlib + +from django.conf import settings # noqa +from django.core.exceptions import ImproperlyConfigured + +from appconf import AppConf + + +def load_path_attr(path): + i = path.rfind(".") + module, attr = path[:i], path[i + 1:] + try: + mod = importlib.import_module(module) + except ImportError as e: + raise ImproperlyConfigured("Error importing {0}: '{1}'".format(module, e)) + try: + attr = getattr(mod, attr) + except AttributeError: + raise ImproperlyConfigured("Module '{0}' does not define a '{1}'".format(module, attr)) + return attr + + +def is_installed(package): + try: + __import__(package) + return True + except ImportError: + return False + + +class GeoNodeClientAppConf(AppConf): + + LAYER_PREVIEW_LIBRARY = 'geoext' + HOOKSET = "geonode.client.hooksets.GeoExtHookSet" + + def configure_hookset(self, value): + return load_path_attr(value)() + + class Meta: + prefix = "geonode_client" diff --git a/geonode/client/hooks.py b/geonode/client/hooks.py new file mode 100644 index 00000000000..e042f0a606f --- /dev/null +++ b/geonode/client/hooks.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +######################################################################### +# +# Copyright (C) 2018 OSGeo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### +from .conf import settings + + +class HookProxy(object): + + def __getattr__(self, attr): + return getattr(settings.GEONODE_CLIENT_HOOKSET, attr) + + +hookset = HookProxy() diff --git a/geonode/client/hooksets.py b/geonode/client/hooksets.py new file mode 100644 index 00000000000..22abd2fc773 --- /dev/null +++ b/geonode/client/hooksets.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +######################################################################### +# +# Copyright (C) 2018 OSGeo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### + + +class GeoExtHookSet(object): + + # Layers + def layer_detail_template(self, context=None): + return 'geoext/layers/layer_geoext_map.html' + + def layer_new_template(self, context=None): + return 'geoext/layers/layer_geoext_map.html' + + def layer_view_template(self, context=None): + return 'geoext/layers/layer_geoext_map.html' + + def layer_edit_template(self, context=None): + return 'geoext/layers/layer_geoext_map.html' + + def layer_update_template(self, context=None): + return 'geoext/layers/layer_geoext_map.html' + + def layer_embed_template(self, context=None): + return 'geoext/layers/layer_geoext_map.html' + + def layer_download_template(self, context=None): + return 'geoext/layers/layer_geoext_map.html' + + # Maps + def map_detail_template(self, context=None): + return 'geoext/maps/map_include.html' + + def map_new_template(self, context=None): + return 'geoext/maps/map_geoexplorer.js' + + def map_view_template(self, context=None): + return 'geoext/maps/map_geoexplorer.js' + + def map_edit_template(self, context=None): + return 'geoext/maps/map_geoexplorer.js' + + def map_update_template(self, context=None): + return 'geoext/maps/map_geoexplorer.js' + + def map_embed_template(self, context=None): + return 'geoext/maps/map_geoexplorer.js' + + def map_download_template(self, context=None): + return 'geoext/maps/map_geoexplorer.js' + + +class LeafletHookSet(object): + + # Layers + def layer_detail_template(self, context=None): + return 'leaflet/layers/layer_leaflet_map.html' + + def layer_new_template(self, context=None): + return 'leaflet/layers/layer_leaflet_map.html' + + def layer_view_template(self, context=None): + return 'leaflet/layers/layer_leaflet_map.html' + + def layer_edit_template(self, context=None): + return 'leaflet/layers/layer_leaflet_map.html' + + def layer_update_template(self, context=None): + return 'leaflet/layers/layer_leaflet_map.html' + + def layer_embed_template(self, context=None): + return 'leaflet/layers/layer_leaflet_map.html' + + def layer_download_template(self, context=None): + return 'leaflet/layers/layer_leaflet_map.html' + + # Maps + def map_detail_template(self, context=None): + return 'leaflet/maps/map_view.html' + + def map_new_template(self, context=None): + return 'leaflet/maps/map_view.html' + + def map_view_template(self, context=None): + return 'leaflet/maps/map_view.html' + + def map_edit_template(self, context=None): + return 'leaflet/maps/map_edit.html' + + def map_update_template(self, context=None): + return 'leaflet/maps/map_edit.html' + + def map_embed_template(self, context=None): + return 'leaflet/maps/map_detail.html' + + def map_download_template(self, context=None): + return 'leaflet/maps/map_embed.html' + + +class ReactHookSet(object): + + # Layers + def layer_detail_template(self, context=None): + return 'geonode-client/layer_map.html' + + def layer_new_template(self, context=None): + return 'geonode-client/layer_map.html' + + def layer_view_template(self, context=None): + return 'geonode-client/layer_map.html' + + def layer_edit_template(self, context=None): + return 'geonode-client/layer_map.html' + + def layer_update_template(self, context=None): + return 'geonode-client/layer_map.html' + + def layer_embed_template(self, context=None): + return 'geonode-client/layer_map.html' + + def layer_download_template(self, context=None): + return 'geonode-client/layer_map.html' + + # Maps + def map_detail_template(self, context=None): + return 'geonode-client/map_detail.html' + + def map_new_template(self, context=None): + return 'geonode-client/map_new.html' + + def map_view_template(self, context=None): + return 'geonode-client/map_view.html' + + def map_edit_template(self, context=None): + return 'geonode-client/edit_map.html' + + def map_update_template(self, context=None): + return 'geonode-client/edit_map.html' + + def map_embed_template(self, context=None): + return 'geonode-client/map_view.html' + + def map_download_template(self, context=None): + return 'geonode-client/map_view.html' diff --git a/geonode/templates/geonode/app_header.html b/geonode/client/templates/geoext/app_header.html similarity index 100% rename from geonode/templates/geonode/app_header.html rename to geonode/client/templates/geoext/app_header.html diff --git a/geonode/templates/geonode/ext_header.html b/geonode/client/templates/geoext/ext_header.html similarity index 100% rename from geonode/templates/geonode/ext_header.html rename to geonode/client/templates/geoext/ext_header.html diff --git a/geonode/templates/geonode/geo_header.html b/geonode/client/templates/geoext/geo_header.html similarity index 100% rename from geonode/templates/geonode/geo_header.html rename to geonode/client/templates/geoext/geo_header.html diff --git a/geonode/templates/geonode/geo_header_debug.html b/geonode/client/templates/geoext/geo_header_debug.html similarity index 100% rename from geonode/templates/geonode/geo_header_debug.html rename to geonode/client/templates/geoext/geo_header_debug.html diff --git a/geonode/templates/geonode/geo_header_mini.html b/geonode/client/templates/geoext/geo_header_mini.html similarity index 100% rename from geonode/templates/geonode/geo_header_mini.html rename to geonode/client/templates/geoext/geo_header_mini.html diff --git a/geonode/layers/templates/layers/layer_geoext_map.html b/geonode/client/templates/geoext/layers/layer_geoext_map.html similarity index 98% rename from geonode/layers/templates/layers/layer_geoext_map.html rename to geonode/client/templates/geoext/layers/layer_geoext_map.html index 9c24bc93ac7..44680a9ca5a 100644 --- a/geonode/layers/templates/layers/layer_geoext_map.html +++ b/geonode/client/templates/geoext/layers/layer_geoext_map.html @@ -1,6 +1,6 @@ -{% include "geonode/ext_header.html" %} -{% include "geonode/app_header.html" %} -{% include "geonode/geo_header.html" %} +{% include "geoext/ext_header.html" %} +{% include "geoext/app_header.html" %} +{% include "geoext/geo_header.html" %} diff --git a/geonode/layers/templates/layers/layer_geoext_map_mini.html b/geonode/client/templates/geoext/layers/layer_geoext_map_mini.html similarity index 98% rename from geonode/layers/templates/layers/layer_geoext_map_mini.html rename to geonode/client/templates/geoext/layers/layer_geoext_map_mini.html index 0034a8ca638..64e832c98b2 100644 --- a/geonode/layers/templates/layers/layer_geoext_map_mini.html +++ b/geonode/client/templates/geoext/layers/layer_geoext_map_mini.html @@ -1,6 +1,6 @@ -{% include "geonode/ext_header.html" %} -{% include "geonode/app_header.html" %} -{% include "geonode/geo_header_mini.html" %} +{% include "geoexet/ext_header.html" %} +{% include "geoexet/app_header.html" %} +{% include "geoexet/geo_header_mini.html" %} diff --git a/geonode/maps/templates/maps/map_geoexplorer.js b/geonode/client/templates/geoext/maps/map_geoexplorer.js similarity index 98% rename from geonode/maps/templates/maps/map_geoexplorer.js rename to geonode/client/templates/geoext/maps/map_geoexplorer.js index fd843ae27ae..9c7327c3a72 100644 --- a/geonode/maps/templates/maps/map_geoexplorer.js +++ b/geonode/client/templates/geoext/maps/map_geoexplorer.js @@ -1,5 +1,5 @@ -{% include 'geonode/ext_header.html' %} -{% include 'geonode/geo_header.html' %} +{% include 'geoext/ext_header.html' %} +{% include 'geoext/geo_header.html' %} diff --git a/geonode/maps/templates/maps/map_include.html b/geonode/client/templates/geoext/maps/map_include.html similarity index 98% rename from geonode/maps/templates/maps/map_include.html rename to geonode/client/templates/geoext/maps/map_include.html index 7a5e08391a9..26286a68e74 100644 --- a/geonode/maps/templates/maps/map_include.html +++ b/geonode/client/templates/geoext/maps/map_include.html @@ -1,6 +1,6 @@ -{% include "geonode/ext_header.html" %} -{% include "geonode/app_header.html" %} -{% include "geonode/geo_header.html" %} +{% include "geoext/ext_header.html" %} +{% include "geoext/app_header.html" %} +{% include "geoext/geo_header.html" %} diff --git a/geonode/maps/templates/maps/map_sdk.js b/geonode/client/templates/geoext/maps/map_sdk.js similarity index 94% rename from geonode/maps/templates/maps/map_sdk.js rename to geonode/client/templates/geoext/maps/map_sdk.js index 2e7b549f7df..068f1fc75d0 100644 --- a/geonode/maps/templates/maps/map_sdk.js +++ b/geonode/client/templates/geoext/maps/map_sdk.js @@ -1,5 +1,5 @@ -{% include 'geonode/ext_header.html' %} -{% include 'geonode/sdk_header.html' %} +{% include 'geoext/ext_header.html' %} +{% include 'geoext/sdk_header.html' %} - {% if preview == 'geoext' %} - {% include 'maps/map_geoexplorer.js' %} - {% elif preview == 'react' %} - {% include 'geonode-client/edit_map.html' %} - {% else %} - {% include 'maps/map_geoexplorer.js' %} - {% endif %} - + {% get_map_edit %} {{ block.super }} {% endblock %} diff --git a/geonode/maps/templates/maps/map_embed.html b/geonode/maps/templates/maps/map_embed.html index 6e87239daea..12d2b083f08 100644 --- a/geonode/maps/templates/maps/map_embed.html +++ b/geonode/maps/templates/maps/map_embed.html @@ -1,9 +1,9 @@ {% load i18n %} {% block head %} - {% include "geonode/ext_header.html" %} - {% include "geonode/app_header.html" %} - {% include "geonode/geo_header.html" %} + {% include "geoext/ext_header.html" %} + {% include "geoext/app_header.html" %} + {% include "geoext/geo_header.html" %} diff --git a/geonode/maps/templates/maps/map_metadata.html b/geonode/maps/templates/maps/map_metadata.html index 74f0803eb54..7e2ecd0bde2 100644 --- a/geonode/maps/templates/maps/map_metadata.html +++ b/geonode/maps/templates/maps/map_metadata.html @@ -9,7 +9,7 @@ {% block title %}{{ map.title }} — {{ block.super }}{% endblock %} {% block head %} - {% include "maps/map_ol2.html" %} + {% include "ol/maps/map_ol2.html" %} {{ block.super }} {% endblock head %} diff --git a/geonode/maps/templates/maps/map_new.html b/geonode/maps/templates/maps/map_new.html index 46d1aea130b..8f744971e97 100644 --- a/geonode/maps/templates/maps/map_new.html +++ b/geonode/maps/templates/maps/map_new.html @@ -2,6 +2,7 @@ {% load i18n %} {% load base_tags %} +{% load client_lib_tags %} {% block title %} {% trans "New Map" %} - {{ block.super }} {% endblock %} {% block head %} @@ -12,14 +13,7 @@ } - {% if preview == 'geoext' %} - {% include 'maps/map_geoexplorer.js' %} - {% elif preview == 'react' %} - {% include 'geonode-client/map_new.html' %} - {% else %} - {% include 'maps/map_geoexplorer.js' %} - {% endif %} - + {% get_map_new %} {{ block.super }} {% endblock %} diff --git a/geonode/maps/templates/maps/map_view.html b/geonode/maps/templates/maps/map_view.html index 5c4ad9a91c5..426b6e4d3b0 100644 --- a/geonode/maps/templates/maps/map_view.html +++ b/geonode/maps/templates/maps/map_view.html @@ -2,6 +2,7 @@ {% load i18n %} {% load base_tags %} +{% load client_lib_tags %} {% block title %} {% trans "Map" %} - {{ block.super }} {% endblock %} @@ -13,13 +14,7 @@ } - {% if preview == 'geoext' %} - {% include 'maps/map_geoexplorer.js' %} - {% elif preview == 'react' %} - {% include 'geonode-client/map_view.html' %} - {% else %} - {% include 'maps/map_geoexplorer.js' %} - {% endif %} + {% get_map_view %} {{ block.super }} {% endblock %} {% block footer %}{% endblock %} diff --git a/geonode/maps/views.py b/geonode/maps/views.py index 01e2be3e392..79c07b6ca2b 100644 --- a/geonode/maps/views.py +++ b/geonode/maps/views.py @@ -165,8 +165,8 @@ def map_detail(request, mapid, snapshot=None, template='maps/map_detail.html'): context_dict["preview"] = getattr( settings, - 'LAYER_PREVIEW_LIBRARY', - '') + 'GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY', + 'geoext') context_dict["crs"] = getattr( settings, 'DEFAULT_MAP_CRS', @@ -335,7 +335,7 @@ def map_metadata(request, mapid, template='maps/map_metadata.html'): "author_form": author_form, "category_form": category_form, "layers": layers, - "preview": getattr(settings, 'LAYER_PREVIEW_LIBRARY', 'leaflet'), + "preview": getattr(settings, 'GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY', 'geoext'), "crs": getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913'), "metadata_author_groups": metadata_author_groups, "GROUP_MANDATORY_RESOURCES": getattr(settings, 'GROUP_MANDATORY_RESOURCES', False), @@ -421,7 +421,7 @@ def map_embed( def map_embed_widget(request, mapid, - template='leaflet_maps/map_embed_widget.html'): + template='leaflet/maps/map_embed_widget.html'): """Display code snippet for embedding widget. :param request: The request from the frontend. @@ -544,8 +544,8 @@ def map_view(request, mapid, snapshot=None, layer_name=None, template='maps/map_ 'map': map_obj, 'preview': getattr( settings, - 'LAYER_PREVIEW_LIBRARY', - '') + 'GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY', + 'geoext') })) @@ -653,8 +653,8 @@ def map_edit(request, mapid, snapshot=None, template='maps/map_edit.html'): 'map': map_obj, 'preview': getattr( settings, - 'LAYER_PREVIEW_LIBRARY', - '') + 'GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY', + 'geoext') })) @@ -690,8 +690,8 @@ def new_map(request, template='maps/map_new.html'): } context_dict["preview"] = getattr( settings, - 'LAYER_PREVIEW_LIBRARY', - '') + 'GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY', + 'geoext') if isinstance(config, HttpResponse): return config else: diff --git a/geonode/messaging/consumer.py b/geonode/messaging/consumer.py index 995daacc049..b0882afddac 100644 --- a/geonode/messaging/consumer.py +++ b/geonode/messaging/consumer.py @@ -21,10 +21,10 @@ import logging import time -from django.conf import settings +# from django.conf import settings from kombu.mixins import ConsumerMixin from geonode.geoserver.signals import geoserver_post_save_local -from geonode.security.views import send_email_consumer, send_email_owner_on_view +from geonode.security.views import send_email_consumer # , send_email_owner_on_view # from geonode.social.signals import notification_post_save_resource2 from geonode.layers.views import layer_view_counter from geonode.layers.models import Layer @@ -144,12 +144,13 @@ def on_consume_ready(self, connection, channel, consumers, **kwargs): def on_layer_viewer(self, body, message): # logger.debug("on_layer_viewer: RECEIVED MSG - body: %r" % (body,)) viewer = body.get("viewer") - owner_layer = body.get("owner_layer") + # owner_layer = body.get("owner_layer") layer_id = body.get("layer_id") layer_view_counter(layer_id, viewer) - if settings.EMAIL_ENABLE: - send_email_owner_on_view(owner_layer, viewer, layer_id) + # TODO Disabled for now. This should be handeld through Notifications + # if settings.EMAIL_ENABLE: + # send_email_owner_on_view(owner_layer, viewer, layer_id) message.ack() logger.info("on_layer_viewer: finished") self._check_message_limit() diff --git a/geonode/people/admin.py b/geonode/people/admin.py index 26f6cacb379..c14e118df3a 100644 --- a/geonode/people/admin.py +++ b/geonode/people/admin.py @@ -70,7 +70,7 @@ class ProfileAdmin(admin.ModelAdmin): form = ProfileChangeForm add_form = ProfileCreationForm change_password_form = AdminPasswordChangeForm - list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff') + list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active') list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups') search_fields = ('username', 'first_name', 'last_name', 'email') ordering = ('username',) diff --git a/geonode/qgis_server/helpers.py b/geonode/qgis_server/helpers.py index 84f24675fcf..20104ba4190 100644 --- a/geonode/qgis_server/helpers.py +++ b/geonode/qgis_server/helpers.py @@ -92,10 +92,10 @@ def validate_django_settings(): raise ImproperlyConfigured( 'QGIS_SERVER_CONFIG setting should be configured.') - if not settings.LAYER_PREVIEW_LIBRARY == 'leaflet': + if not settings.GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY == 'leaflet': raise ImproperlyConfigured( 'QGIS Server at the moment only works with ' - 'LAYER_PREVIEW_LIBRARY = leaflet.') + 'GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY = leaflet.') # Check OGC Server settings default_ogc_backend = settings.OGC_SERVER['default'] diff --git a/geonode/security/models.py b/geonode/security/models.py index fdc0768261e..7350c0356c1 100644 --- a/geonode/security/models.py +++ b/geonode/security/models.py @@ -17,32 +17,20 @@ # along with this program. If not, see . # ######################################################################### -from geonode import geoserver -from geonode.decorators import on_ogc_backend -from lxml import etree - -try: - import json -except ImportError: - from django.utils import simplejson as json import logging -import traceback -import requests - -from requests.auth import HTTPBasicAuth +from django.conf import settings from django.contrib.auth import get_user_model - -from django.contrib.contenttypes.models import ContentType -from django.contrib.auth import login -from django.contrib.auth.models import Group, Permission +from django.contrib.auth.models import Group from geonode.groups.models import GroupProfile -from django.core.exceptions import ObjectDoesNotExist -from django.conf import settings -from guardian.utils import get_user_obj_perms_model from guardian.shortcuts import assign_perm, get_groups_with_perms -from ..services.enumerations import CASCADED +from .utils import (get_users_with_perms, + set_geofence_all, + set_geofence_owner, + set_geofence_group, + set_owner_permissions, + remove_object_permissions) logger = logging.getLogger("geonode.security.models") @@ -65,36 +53,6 @@ "GEOFENCE_SECURITY_ENABLED", False) -def get_users_with_perms(obj): - """ - Override of the Guardian get_users_with_perms - """ - ctype = ContentType.objects.get_for_model(obj) - permissions = {} - PERMISSIONS_TO_FETCH = ADMIN_PERMISSIONS + LAYER_ADMIN_PERMISSIONS - - for perm in Permission.objects.filter(codename__in=PERMISSIONS_TO_FETCH, content_type_id=ctype.id): - permissions[perm.id] = perm.codename - - user_model = get_user_obj_perms_model(obj) - users_with_perms = user_model.objects.filter(object_pk=obj.pk, - content_type_id=ctype.id, - permission_id__in=permissions).values('user_id', 'permission_id') - - users = {} - for item in users_with_perms: - if item['user_id'] in users: - users[item['user_id']].append(permissions[item['permission_id']]) - else: - users[item['user_id']] = [permissions[item['permission_id']], ] - - profiles = {} - for profile in get_user_model().objects.filter(id__in=users.keys()): - profiles[profile] = users[profile.id] - - return profiles - - class PermissionLevelError(Exception): pass @@ -269,391 +227,3 @@ def set_permissions(self, perm_spec): assign_perm(perm, group, self.layer) else: assign_perm(perm, group, self.get_self_resource()) - - -def get_geofence_rules_count(): - """invalidate GeoFence Cache Rules""" - try: - url = settings.OGC_SERVER['default']['LOCATION'] - user = settings.OGC_SERVER['default']['USER'] - passwd = settings.OGC_SERVER['default']['PASSWORD'] - # Check first that the rules does not exist already - """ - curl -X GET -u admin:geoserver \ - http://:/geoserver/geofence/rest/rules/count.json - """ - headers = {'Content-type': 'application/json'} - r = requests.get(url + 'geofence/rest/rules/count.json', - headers=headers, - auth=HTTPBasicAuth(user, passwd)) - if (r.status_code < 200 or r.status_code > 201): - logger.warning("Could not retrieve GeoFence Rules count.") - - rules_objs = json.loads(r.text) - rules_count = rules_objs['count'] - return int(rules_count) - except: - tb = traceback.format_exc() - logger.debug(tb) - return -1 - - -@on_ogc_backend(geoserver.BACKEND_PACKAGE) -def set_geofence_invalidate_cache(): - """invalidate GeoFence Cache Rules""" - if GEOFENCE_SECURITY_ENABLED: - try: - url = settings.OGC_SERVER['default']['LOCATION'] - user = settings.OGC_SERVER['default']['USER'] - passwd = settings.OGC_SERVER['default']['PASSWORD'] - # Check first that the rules does not exist already - """ - curl -X GET -u admin:geoserver \ - http://:/geoserver/rest/ruleCache/invalidate - """ - r = requests.put(url + 'rest/ruleCache/invalidate', - auth=HTTPBasicAuth(user, passwd)) - - if (r.status_code < 200 or r.status_code > 201): - logger.warning("Could not Invalidate GeoFence Rules.") - except Exception: - tb = traceback.format_exc() - logger.debug(tb) - raise - - -@on_ogc_backend(geoserver.BACKEND_PACKAGE) -def set_geofence_all(instance): - """assign access permissions to all users - - This method is only relevant to Layer instances that have their - underlying data managed by geoserver, meaning: - - * layers that are not associated with a Service - * layers that are associated with a Service that is being CASCADED through - geoserver - - """ - - resource = instance.get_self_resource() - logger.debug("Inside set_geofence_all for instance {}".format(instance)) - try: - workspace = _get_layer_workspace(resource.layer) - logger.debug("going to work in workspace {!r}".format(workspace)) - except (ObjectDoesNotExist, AttributeError, RuntimeError): - # This is either not a layer (if raised AttributeError) or it is - # a layer that is not manageable by geofence (if raised - # RuntimeError) so we have nothing to do - return - try: - url = settings.OGC_SERVER['default']['LOCATION'] - user = settings.OGC_SERVER['default']['USER'] - passwd = settings.OGC_SERVER['default']['PASSWORD'] - # Check first that the rules does not exist already - """ - curl -X GET -u admin:geoserver -H "Content-Type: application/json" \ - http://:/geoserver/geofence/rest/rules.json?layer= - """ - headers = {'Content-type': 'application/json'} - r = requests.get(url + 'geofence/rest/rules.json?layer=' + resource.layer.name, - headers=headers, - auth=HTTPBasicAuth(user, passwd)) - - rules_already_present = False - if (r.status_code < 200 or r.status_code > 201): - logger.warning("Could not GET GeoServer Rules for Layer " + str(resource.layer.name)) - else: - try: - rules_objs = json.loads(r.text) - rules_count = rules_objs['count'] - rules = rules_objs['rules'] - if rules_count > 1: - for rule in rules: - if rule['userName'] is None and rule['access'] == 'ALLOW': - rules_already_present = True - except Exception: - logger.debug("Response [{}] : {}".format(r.status_code, r.text)) - raise - - # Create GeoFence Rules for ANONYMOUS to the Layer - """ - curl -X POST -u admin:geoserver -H "Content-Type: text/xml" -d \ - "geonode{layer}ALLOW" \ - http://:/geoserver/geofence/rest/rules - """ - rules_count = get_geofence_rules_count() - headers = {'Content-type': 'application/xml'} - payload = _get_geofence_payload( - layer=resource.layer.name, - workspace=workspace, - access="ALLOW" - ) - - if not rules_already_present: - response = requests.post( - url + 'geofence/rest/rules', - headers=headers, - data=payload, - auth=HTTPBasicAuth(user, passwd) - ) - if response.status_code not in (200, 201): - logger.debug( - "Response {!r} : {}".format(r.status_code, r.text)) - raise RuntimeError("Could not ADD GeoServer ANONYMOUS Rule " - "for Layer {}".format(resource.layer.name)) - except Exception: - tb = traceback.format_exc() - logger.debug(tb) - raise - finally: - set_geofence_invalidate_cache() - - -@on_ogc_backend(geoserver.BACKEND_PACKAGE) -def set_geofence_owner(instance, username=None, view_perms=False, download_perms=False): - """Assign access permissions to owner user - - This function uses the geoserver REST API in order to contact geofence. - The request performs a similar function to the one in the following cURL - snippet: - - curl -X POST -u {admin_user}:{admin_password} \ - -H "Content-Type: text/xml" \ - -d "{user}geonode \ - {layer}ALLOW" \ - http://:/geoserver/geofence/rest/rules - - """ - - resource = instance.get_self_resource() - try: - workspace = _get_layer_workspace(resource.layer) - except (ObjectDoesNotExist, AttributeError, RuntimeError): - # resource is either not a layer (if raised AttributeError) or - # a layer that is not manageable by geofence (if raised - # RuntimeError) so we have nothing to do - pass - else: - services = ( - (["WMS", "GWC"] if view_perms else []) + - (["WFS", "WCS", "WPS"] if download_perms else []) - ) - try: - for service in services: - _update_geofence_rule( - layer=resource.layer.name, - workspace=workspace, - service=service, - user=username - ) - except Exception: - tb = traceback.format_exc() - logger.debug(tb) - raise - finally: - set_geofence_invalidate_cache() - - -@on_ogc_backend(geoserver.BACKEND_PACKAGE) -def set_geofence_group(instance, groupname, view_perms=False, - download_perms=False): - """assign access permissions to owner group""" - resource = instance.get_self_resource() - try: - workspace = _get_layer_workspace(resource.layer) - except (ObjectDoesNotExist, AttributeError, RuntimeError): - # resource is either not a layer (if raised AttributeError) or - # a layer that is not manageable by geofence (if raised - # RuntimeError) so we have nothing to do - pass - else: - if groupname: - services = ( - (["WMS", "GWC"] if view_perms else []) + - (["WFS", "WCS", "WPS"] if download_perms else []) - ) - try: - for service in services: - _update_geofence_rule( - layer=resource.layer.name, - workspace=workspace, - group=groupname, - service=service - ) - except Exception: - tb = traceback.format_exc() - logger.debug(tb) - raise - finally: - set_geofence_invalidate_cache() - - -def set_owner_permissions(resource): - """assign all admin permissions to the owner""" - if resource.polymorphic_ctype: - # Set the GeoFence Owner Rule - if resource.polymorphic_ctype.name == 'layer': - # Assign GeoFence Layer Access to Owner - geofence_user = str(resource.owner) - if "AnonymousUser" in geofence_user: - geofence_user = None - if GEOFENCE_SECURITY_ENABLED: - set_geofence_owner(resource, username=geofence_user) - for perm in LAYER_ADMIN_PERMISSIONS: - assign_perm(perm, resource.owner, resource.layer) - - for perm in ADMIN_PERMISSIONS: - assign_perm(perm, resource.owner, resource.get_self_resource()) - - -def remove_object_permissions(instance): - """Remove object permissions on given resource. - - If is a layer removes the layer specific permissions then the - resourcebase permissions - - """ - - from guardian.models import UserObjectPermission, GroupObjectPermission - resource = instance.get_self_resource() - if hasattr(resource, "layer"): - try: - UserObjectPermission.objects.filter( - content_type=ContentType.objects.get_for_model(resource.layer), - object_pk=instance.id - ).delete() - GroupObjectPermission.objects.filter( - content_type=ContentType.objects.get_for_model(resource.layer), - object_pk=instance.id - ).delete() - if GEOFENCE_SECURITY_ENABLED: - # Scan GeoFence Rules associated to the Layer - """ - curl -u admin:geoserver - http://:/geoserver/geofence/rest/rules.json?workspace=geonode&layer={layer} - """ - url = settings.OGC_SERVER['default']['LOCATION'] - user = settings.OGC_SERVER['default']['USER'] - passwd = settings.OGC_SERVER['default']['PASSWORD'] - headers = {'Content-type': 'application/json'} - workspace = _get_layer_workspace(resource.layer) - r = requests.get( - "{}geofence/rest/rules.json?workspace={}&layer={}".format( - url, workspace, resource.layer.name), - headers=headers, - auth=HTTPBasicAuth(user, passwd) - ) - if (r.status_code >= 200): - gs_rules = r.json() - r_ids = [] - if gs_rules and gs_rules['rules']: - for r in gs_rules['rules']: - if r['layer'] and r['layer'] == resource.layer.name: - r_ids.append(r['id']) - - # Delete GeoFence Rules associated to the Layer - # curl -X DELETE -u admin:geoserver http://:/geoserver/geofence/rest/rules/id/{r_id} - for i, r_id in enumerate(r_ids): - r = requests.delete(url + 'geofence/rest/rules/id/' + str(r_id), - headers=headers, - auth=HTTPBasicAuth(user, passwd)) - if (r.status_code < 200 or r.status_code > 201): - msg = "Could not DELETE GeoServer Rule for Layer " - msg = msg + str(resource.layer.name) - e = Exception(msg) - logger.debug("Response [{}] : {}".format(r.status_code, r.text)) - raise e - except (ObjectDoesNotExist, RuntimeError): - pass # This layer is not manageable by geofence - except Exception: - tb = traceback.format_exc() - logger.debug(tb) - raise - finally: - set_geofence_invalidate_cache() - - UserObjectPermission.objects.filter(content_type=ContentType.objects.get_for_model(resource), - object_pk=instance.id).delete() - GroupObjectPermission.objects.filter(content_type=ContentType.objects.get_for_model(resource), - object_pk=instance.id).delete() - - -# Logic to login a user automatically when it has successfully -# activated an account: -def autologin(sender, **kwargs): - user = kwargs['user'] - request = kwargs['request'] - # Manually setting the default user backed to avoid the - # 'User' object has no attribute 'backend' error - user.backend = 'django.contrib.auth.backends.ModelBackend' - # This login function does not need password. - login(request, user) - -# FIXME(Ariel): Replace this signal with the one from django-user-accounts -# user_activated.connect(autologin) - - -def _get_layer_workspace(layer): - """Get the workspace where the input layer belongs""" - default_workspace = getattr(settings, "DEFAULT_WORKSPACE", "geonode") - try: - if layer.service.method == CASCADED: - workspace = getattr( - settings, "CASCADE_WORKSPACE", default_workspace) - else: - raise RuntimeError("Layer is not cascaded") - except AttributeError: # layer does not have a service - workspace = default_workspace - return workspace - - -def _get_geofence_payload(layer, workspace, access, user=None, group=None, - service=None): - rules_count = get_geofence_rules_count() - root_el = etree.Element("Rule") - if user is not None: - username_el = etree.SubElement(root_el, "userName") - username_el.text = user - priority_el = etree.SubElement(root_el, "priority") - priority_el.text = str(rules_count - 1) - if group is not None: - role_el = etree.SubElement(root_el, "roleName") - role_el.text = "ROLE_{}".format(group.upper()) - workspace_el = etree.SubElement(root_el, "workspace") - workspace_el.text = workspace - layer_el = etree.SubElement(root_el, "layer") - layer_el.text = layer - access_el = etree.SubElement(root_el, "access") - access_el.text = access - if service is not None: - service_el = etree.SubElement(root_el, "service") - service_el.text = service - return etree.tostring(root_el) - - -def _update_geofence_rule(layer, workspace, service, user=None, group=None): - payload = _get_geofence_payload( - layer=layer, - workspace=workspace, - access="ALLOW", - user=user, - group=group, - service=service - ) - logger.debug("request data: {}".format(payload)) - response = requests.post( - "{base_url}geofence/rest/rules".format( - base_url=settings.OGC_SERVER['default']['LOCATION']), - data=payload, - headers={ - 'Content-type': 'application/xml' - }, - auth=HTTPBasicAuth( - username=settings.OGC_SERVER['default']['USER'], - password=settings.OGC_SERVER['default']['PASSWORD'] - ) - ) - if response.status_code not in (200, 201): - msg = ("Could not ADD GeoServer User {!r} Rule for " - "Layer {!r}".format(user, layer)) - raise RuntimeError(msg) diff --git a/geonode/security/utils.py b/geonode/security/utils.py new file mode 100644 index 00000000000..cf35630a96e --- /dev/null +++ b/geonode/security/utils.py @@ -0,0 +1,548 @@ +# -*- coding: utf-8 -*- +######################################################################### +# +# Copyright (C) 2018 OSGeo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### +from geonode import geoserver +from geonode.decorators import on_ogc_backend +from lxml import etree + +try: + import json +except ImportError: + from django.utils import simplejson as json +import logging +import traceback +import requests +import models + +from requests.auth import HTTPBasicAuth +from django.conf import settings +from django.db.models import Q +from django.contrib.auth import get_user_model +from django.contrib.contenttypes.models import ContentType +# from django.contrib.auth import login +from django.contrib.auth.models import Group, Permission +from django.core.exceptions import ObjectDoesNotExist +from guardian.utils import get_user_obj_perms_model +from guardian.shortcuts import assign_perm +from geonode.groups.models import GroupProfile +from ..services.enumerations import CASCADED + +logger = logging.getLogger("geonode.security.utils") + + +def get_visible_resources(queryset, + user, + admin_approval_required=False, + unpublished_not_visible=False, + private_groups_not_visibile=False): + is_admin = False + is_manager = False + if user: + is_admin = user.is_superuser if user else False + try: + is_manager = user.groupmember_set.all().filter(role='manager').exists() + except: + is_manager = False + + # Get the list of objects the user has access to + anonymous_group = None + public_groups = GroupProfile.objects.exclude(access="private").values('group') + groups = [] + group_list_all = [] + manager_groups = [] + try: + group_list_all = user.group_list_all().values('group') + except: + pass + try: + manager_groups = Group.objects.filter( + name__in=user.groupmember_set.filter(role="manager").values_list("group__slug", flat=True)) + except: + pass + try: + anonymous_group = Group.objects.get(name='anonymous') + if anonymous_group and anonymous_group not in groups: + groups.append(anonymous_group) + except: + pass + + filter_set = queryset + + if admin_approval_required: + if not is_admin: + if is_manager: + filter_set = filter_set.filter( + Q(is_published=True) | + Q(group__in=groups) | + Q(group__in=manager_groups) | + Q(group__in=group_list_all) | + Q(group__in=public_groups) | + Q(owner__username__iexact=str(user))) + elif user: + filter_set = filter_set.filter( + Q(is_published=True) | + Q(group__in=groups) | + Q(group__in=group_list_all) | + Q(group__in=public_groups) | + Q(owner__username__iexact=str(user))) + else: + filter_set = filter_set.filter( + Q(is_published=True) | + Q(group__in=public_groups) | + Q(group__in=groups)) + + if unpublished_not_visible: + if not is_admin: + if user: + filter_set = filter_set.exclude( + Q(is_published=False) & ~( + Q(owner__username__iexact=str(user)) | Q(group__in=group_list_all))) + else: + filter_set = filter_set.exclude(is_published=False) + + if private_groups_not_visibile: + if not is_admin: + private_groups = GroupProfile.objects.filter(access="private").values('group') + if user: + filter_set = filter_set.exclude( + Q(group__in=private_groups) & ~( + Q(owner__username__iexact=str(user)) | Q(group__in=group_list_all))) + else: + filter_set = filter_set.exclude(group__in=private_groups) + + return filter_set + + +def get_users_with_perms(obj): + """ + Override of the Guardian get_users_with_perms + """ + ctype = ContentType.objects.get_for_model(obj) + permissions = {} + PERMISSIONS_TO_FETCH = models.ADMIN_PERMISSIONS + models.LAYER_ADMIN_PERMISSIONS + + for perm in Permission.objects.filter(codename__in=PERMISSIONS_TO_FETCH, content_type_id=ctype.id): + permissions[perm.id] = perm.codename + + user_model = get_user_obj_perms_model(obj) + users_with_perms = user_model.objects.filter(object_pk=obj.pk, + content_type_id=ctype.id, + permission_id__in=permissions).values('user_id', 'permission_id') + + users = {} + for item in users_with_perms: + if item['user_id'] in users: + users[item['user_id']].append(permissions[item['permission_id']]) + else: + users[item['user_id']] = [permissions[item['permission_id']], ] + + profiles = {} + for profile in get_user_model().objects.filter(id__in=users.keys()): + profiles[profile] = users[profile.id] + + return profiles + + +@on_ogc_backend(geoserver.BACKEND_PACKAGE) +def get_geofence_rules_count(): + """invalidate GeoFence Cache Rules""" + try: + url = settings.OGC_SERVER['default']['LOCATION'] + user = settings.OGC_SERVER['default']['USER'] + passwd = settings.OGC_SERVER['default']['PASSWORD'] + # Check first that the rules does not exist already + """ + curl -X GET -u admin:geoserver \ + http://:/geoserver/geofence/rest/rules/count.json + """ + headers = {'Content-type': 'application/json'} + r = requests.get(url + 'geofence/rest/rules/count.json', + headers=headers, + auth=HTTPBasicAuth(user, passwd)) + if (r.status_code < 200 or r.status_code > 201): + logger.warning("Could not retrieve GeoFence Rules count.") + + rules_objs = json.loads(r.text) + rules_count = rules_objs['count'] + return int(rules_count) + except: + tb = traceback.format_exc() + logger.debug(tb) + return -1 + + +@on_ogc_backend(geoserver.BACKEND_PACKAGE) +def set_geofence_invalidate_cache(): + """invalidate GeoFence Cache Rules""" + if models.GEOFENCE_SECURITY_ENABLED: + try: + url = settings.OGC_SERVER['default']['LOCATION'] + user = settings.OGC_SERVER['default']['USER'] + passwd = settings.OGC_SERVER['default']['PASSWORD'] + # Check first that the rules does not exist already + """ + curl -X GET -u admin:geoserver \ + http://:/geoserver/rest/ruleCache/invalidate + """ + r = requests.put(url + 'rest/ruleCache/invalidate', + auth=HTTPBasicAuth(user, passwd)) + + if (r.status_code < 200 or r.status_code > 201): + logger.warning("Could not Invalidate GeoFence Rules.") + except Exception: + tb = traceback.format_exc() + logger.debug(tb) + raise + + +@on_ogc_backend(geoserver.BACKEND_PACKAGE) +def set_geofence_all(instance): + """assign access permissions to all users + + This method is only relevant to Layer instances that have their + underlying data managed by geoserver, meaning: + + * layers that are not associated with a Service + * layers that are associated with a Service that is being CASCADED through + geoserver + + """ + + resource = instance.get_self_resource() + logger.debug("Inside set_geofence_all for instance {}".format(instance)) + try: + workspace = _get_layer_workspace(resource.layer) + logger.debug("going to work in workspace {!r}".format(workspace)) + except (ObjectDoesNotExist, AttributeError, RuntimeError): + # This is either not a layer (if raised AttributeError) or it is + # a layer that is not manageable by geofence (if raised + # RuntimeError) so we have nothing to do + return + try: + url = settings.OGC_SERVER['default']['LOCATION'] + user = settings.OGC_SERVER['default']['USER'] + passwd = settings.OGC_SERVER['default']['PASSWORD'] + # Check first that the rules does not exist already + """ + curl -X GET -u admin:geoserver -H "Content-Type: application/json" \ + http://:/geoserver/geofence/rest/rules.json?layer= + """ + headers = {'Content-type': 'application/json'} + r = requests.get(url + 'geofence/rest/rules.json?layer=' + resource.layer.name, + headers=headers, + auth=HTTPBasicAuth(user, passwd)) + + rules_already_present = False + if (r.status_code < 200 or r.status_code > 201): + logger.warning("Could not GET GeoServer Rules for Layer " + str(resource.layer.name)) + else: + try: + rules_objs = json.loads(r.text) + rules_count = rules_objs['count'] + rules = rules_objs['rules'] + if rules_count > 1: + for rule in rules: + if rule['userName'] is None and rule['access'] == 'ALLOW': + rules_already_present = True + except Exception: + logger.debug("Response [{}] : {}".format(r.status_code, r.text)) + raise + + # Create GeoFence Rules for ANONYMOUS to the Layer + """ + curl -X POST -u admin:geoserver -H "Content-Type: text/xml" -d \ + "geonode{layer}ALLOW" \ + http://:/geoserver/geofence/rest/rules + """ + rules_count = get_geofence_rules_count() + headers = {'Content-type': 'application/xml'} + payload = _get_geofence_payload( + layer=resource.layer.name, + workspace=workspace, + access="ALLOW" + ) + + if not rules_already_present: + response = requests.post( + url + 'geofence/rest/rules', + headers=headers, + data=payload, + auth=HTTPBasicAuth(user, passwd) + ) + if response.status_code not in (200, 201): + logger.debug( + "Response {!r} : {}".format(r.status_code, r.text)) + raise RuntimeError("Could not ADD GeoServer ANONYMOUS Rule " + "for Layer {}".format(resource.layer.name)) + except Exception: + tb = traceback.format_exc() + logger.debug(tb) + raise + finally: + set_geofence_invalidate_cache() + + +@on_ogc_backend(geoserver.BACKEND_PACKAGE) +def set_geofence_owner(instance, username=None, view_perms=False, download_perms=False): + """Assign access permissions to owner user + + This function uses the geoserver REST API in order to contact geofence. + The request performs a similar function to the one in the following cURL + snippet: + + curl -X POST -u {admin_user}:{admin_password} \ + -H "Content-Type: text/xml" \ + -d "{user}geonode \ + {layer}ALLOW" \ + http://:/geoserver/geofence/rest/rules + + """ + + resource = instance.get_self_resource() + try: + workspace = _get_layer_workspace(resource.layer) + except (ObjectDoesNotExist, AttributeError, RuntimeError): + # resource is either not a layer (if raised AttributeError) or + # a layer that is not manageable by geofence (if raised + # RuntimeError) so we have nothing to do + pass + else: + services = ( + (["WMS", "GWC"] if view_perms else []) + + (["WFS", "WCS", "WPS"] if download_perms else []) + ) + try: + for service in services: + _update_geofence_rule( + layer=resource.layer.name, + workspace=workspace, + service=service, + user=username + ) + except Exception: + tb = traceback.format_exc() + logger.debug(tb) + raise + finally: + set_geofence_invalidate_cache() + + +@on_ogc_backend(geoserver.BACKEND_PACKAGE) +def set_geofence_group(instance, groupname, view_perms=False, + download_perms=False): + """assign access permissions to owner group""" + resource = instance.get_self_resource() + try: + workspace = _get_layer_workspace(resource.layer) + except (ObjectDoesNotExist, AttributeError, RuntimeError): + # resource is either not a layer (if raised AttributeError) or + # a layer that is not manageable by geofence (if raised + # RuntimeError) so we have nothing to do + pass + else: + if groupname: + services = ( + (["WMS", "GWC"] if view_perms else []) + + (["WFS", "WCS", "WPS"] if download_perms else []) + ) + try: + for service in services: + _update_geofence_rule( + layer=resource.layer.name, + workspace=workspace, + group=groupname, + service=service + ) + except Exception: + tb = traceback.format_exc() + logger.debug(tb) + raise + finally: + set_geofence_invalidate_cache() + + +def set_owner_permissions(resource): + """assign all admin permissions to the owner""" + if resource.polymorphic_ctype: + # Set the GeoFence Owner Rule + if resource.polymorphic_ctype.name == 'layer': + # Assign GeoFence Layer Access to Owner + geofence_user = str(resource.owner) + if "AnonymousUser" in geofence_user: + geofence_user = None + if models.GEOFENCE_SECURITY_ENABLED: + set_geofence_owner(resource, username=geofence_user) + for perm in models.LAYER_ADMIN_PERMISSIONS: + assign_perm(perm, resource.owner, resource.layer) + + for perm in models.ADMIN_PERMISSIONS: + assign_perm(perm, resource.owner, resource.get_self_resource()) + + +def remove_object_permissions(instance): + """Remove object permissions on given resource. + + If is a layer removes the layer specific permissions then the + resourcebase permissions + + """ + + from guardian.models import UserObjectPermission, GroupObjectPermission + resource = instance.get_self_resource() + if hasattr(resource, "layer"): + try: + UserObjectPermission.objects.filter( + content_type=ContentType.objects.get_for_model(resource.layer), + object_pk=instance.id + ).delete() + GroupObjectPermission.objects.filter( + content_type=ContentType.objects.get_for_model(resource.layer), + object_pk=instance.id + ).delete() + if models.GEOFENCE_SECURITY_ENABLED: + # Scan GeoFence Rules associated to the Layer + """ + curl -u admin:geoserver + http://:/geoserver/geofence/rest/rules.json?workspace=geonode&layer={layer} + """ + url = settings.OGC_SERVER['default']['LOCATION'] + user = settings.OGC_SERVER['default']['USER'] + passwd = settings.OGC_SERVER['default']['PASSWORD'] + headers = {'Content-type': 'application/json'} + workspace = _get_layer_workspace(resource.layer) + r = requests.get( + "{}geofence/rest/rules.json?workspace={}&layer={}".format( + url, workspace, resource.layer.name), + headers=headers, + auth=HTTPBasicAuth(user, passwd) + ) + if (r.status_code >= 200): + gs_rules = r.json() + r_ids = [] + if gs_rules and gs_rules['rules']: + for r in gs_rules['rules']: + if r['layer'] and r['layer'] == resource.layer.name: + r_ids.append(r['id']) + + # Delete GeoFence Rules associated to the Layer + # curl -X DELETE -u admin:geoserver http://:/geoserver/geofence/rest/rules/id/{r_id} + for i, r_id in enumerate(r_ids): + r = requests.delete(url + 'geofence/rest/rules/id/' + str(r_id), + headers=headers, + auth=HTTPBasicAuth(user, passwd)) + if (r.status_code < 200 or r.status_code > 201): + msg = "Could not DELETE GeoServer Rule for Layer " + msg = msg + str(resource.layer.name) + e = Exception(msg) + logger.debug("Response [{}] : {}".format(r.status_code, r.text)) + raise e + except (ObjectDoesNotExist, RuntimeError): + pass # This layer is not manageable by geofence + except Exception: + tb = traceback.format_exc() + logger.debug(tb) + raise + finally: + set_geofence_invalidate_cache() + + UserObjectPermission.objects.filter(content_type=ContentType.objects.get_for_model(resource), + object_pk=instance.id).delete() + GroupObjectPermission.objects.filter(content_type=ContentType.objects.get_for_model(resource), + object_pk=instance.id).delete() + + +# # Logic to login a user automatically when it has successfully +# # activated an account: +# def autologin(sender, **kwargs): +# user = kwargs['user'] +# request = kwargs['request'] +# # Manually setting the default user backed to avoid the +# # 'User' object has no attribute 'backend' error +# user.backend = 'django.contrib.auth.backends.ModelBackend' +# # This login function does not need password. +# login(request, user) +# +# # FIXME(Ariel): Replace this signal with the one from django-user-accounts +# # user_activated.connect(autologin) + + +def _get_layer_workspace(layer): + """Get the workspace where the input layer belongs""" + default_workspace = getattr(settings, "DEFAULT_WORKSPACE", "geonode") + try: + if layer.service.method == CASCADED: + workspace = getattr( + settings, "CASCADE_WORKSPACE", default_workspace) + else: + raise RuntimeError("Layer is not cascaded") + except AttributeError: # layer does not have a service + workspace = default_workspace + return workspace + + +def _get_geofence_payload(layer, workspace, access, user=None, group=None, + service=None): + rules_count = get_geofence_rules_count() + root_el = etree.Element("Rule") + if user is not None: + username_el = etree.SubElement(root_el, "userName") + username_el.text = user + priority_el = etree.SubElement(root_el, "priority") + priority_el.text = str(rules_count - 1) + if group is not None: + role_el = etree.SubElement(root_el, "roleName") + role_el.text = "ROLE_{}".format(group.upper()) + workspace_el = etree.SubElement(root_el, "workspace") + workspace_el.text = workspace + layer_el = etree.SubElement(root_el, "layer") + layer_el.text = layer + access_el = etree.SubElement(root_el, "access") + access_el.text = access + if service is not None: + service_el = etree.SubElement(root_el, "service") + service_el.text = service + return etree.tostring(root_el) + + +def _update_geofence_rule(layer, workspace, service, user=None, group=None): + payload = _get_geofence_payload( + layer=layer, + workspace=workspace, + access="ALLOW", + user=user, + group=group, + service=service + ) + logger.debug("request data: {}".format(payload)) + response = requests.post( + "{base_url}geofence/rest/rules".format( + base_url=settings.OGC_SERVER['default']['LOCATION']), + data=payload, + headers={ + 'Content-type': 'application/xml' + }, + auth=HTTPBasicAuth( + username=settings.OGC_SERVER['default']['USER'], + password=settings.OGC_SERVER['default']['PASSWORD'] + ) + ) + if response.status_code not in (200, 201): + msg = ("Could not ADD GeoServer User {!r} Rule for " + "Layer {!r}".format(user, layer)) + raise RuntimeError(msg) diff --git a/geonode/services/templates/services/service_detail.html b/geonode/services/templates/services/service_detail.html index f225890562a..2b6451e2ab4 100644 --- a/geonode/services/templates/services/service_detail.html +++ b/geonode/services/templates/services/service_detail.html @@ -2,9 +2,7 @@ {% load i18n %} {% load guardian_tags %} {% block head %} -{% include "geonode/ext_header.html" %} -{% include "geonode/app_header.html" %} -{% include "geonode/geo_header.html" %} + {{ block.super }}