Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 2 additions & 28 deletions geoportal/indexes_mixin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import ujson as json

from django.contrib.gis.geos import Polygon

from giscube.models import Category
from giscube.utils import get_giscube_id
from giscube.utils import get_giscube_id, prepare_output_data
from giscube_search.base_index import BaseGeomIndexMixin, BaseModelIndex


Expand All @@ -27,36 +25,12 @@ def prepare_children(self, obj):

def prepare_output_data(self, obj):
data = super().prepare_output_data(obj)
data['giscube_id'] = get_giscube_id(obj)
data['private'] = not obj.anonymous_view
data['category_id'] = obj.category.pk if obj.category else None
data = prepare_output_data(obj, data)
data['title'] = self.prepare_title(obj)
data['description'] = obj.description
data['keywords'] = obj.keywords
data['group'] = True
data['has_children'] = True
data['children'] = self.prepare_children(obj)
data['legend'] = getattr(obj, 'legend', None)
data['visible_on_geoportal'] = getattr(obj, 'visible_on_geoportal', False)
data['options'] = json.loads(getattr(obj, 'options', '{}') or '{}')
data['catalog'] = (obj.category.title or '').split(Category.SEPARATOR) if obj.category else []
data['catalog_icon'] = self.get_catalog_icon(obj, data['children'])
data['catalog_color'] = obj.catalog_color if hasattr(obj, 'catalog_color') else None
data['filtered_fields'] = [item.strip() for item in obj.filtered_fields.split(',')] if hasattr(obj, 'filtered_fields') and obj.filtered_fields else None
if hasattr(obj, "get_filters"):
data['filters'] = obj.get_filters()
metadata_data = [
'date', 'language', 'category.name', 'information', 'provider_name', 'provider_web', 'provider_email',
'summary', 'bbox'
]
metadata_data_keys = [
'date', 'language', 'category', 'information', 'provider_name', 'provider_web', 'provider_email',
'summary', 'bbox'
]
metadata = {}
for k, x in zip(metadata_data_keys, metadata_data):
metadata[k] = self.get_value(obj, 'metadata.%s' % x)
data['metadata'] = metadata
return data

def prepare_search_data(self, obj):
Expand Down
5 changes: 3 additions & 2 deletions giscube/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from .django import (AdminEmailHandler, RecursionException, check_recursion, get_cls, get_version,
unique_service_directory)
from .file import extract_zipfile, find_file, zipfile_find_file
from .giscube import get_giscube_id
from .giscube import get_giscube_id, prepare_output_data, prepare_children
from .string import env_string_parse
from .url import full_url, remove_app_url, url_slash_join
from .wms import get_service_wms_bbox, get_wms_layers
Expand All @@ -15,5 +15,6 @@
'get_giscube_id', 'unique_service_directory',
'env_string_parse',
'full_url', 'remove_app_url', 'url_slash_join',
'get_wms_layers', 'get_service_wms_bbox'
'get_wms_layers', 'get_service_wms_bbox',
'prepare_output_data', 'prepare_children'
]
98 changes: 98 additions & 0 deletions giscube/utils/giscube.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import datetime
import ujson as json

from django.apps import apps
from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from django.urls import reverse

from .url import url_slash_join


_content_types = {}
Expand All @@ -17,3 +25,93 @@ def get_giscube_id(item):

if content_type_id:
return '%s.%s' % (content_type_id, item.pk)


def fix_data_value(value):
if value:
if isinstance(value, (datetime.datetime, datetime.date)):
value = value.isoformat()
return value


def get_value(obj, field):
attrs = field.split('.')
value = obj
for attr in attrs:
if value:
try:
value = getattr(value, attr)
except ObjectDoesNotExist:
value = None
break
else:
value = fix_data_value(value)
else:
break
return value


def prepare_output_data(obj, data={}):
data['giscube_id'] = get_giscube_id(obj)
data['private'] = not obj.anonymous_view
data['category_id'] = obj.category.pk if obj.category else None

data['description'] = obj.description
data['keywords'] = obj.keywords
data['group'] = True
data['has_children'] = True

data['legend'] = getattr(obj, 'legend', None)
data['visible_on_geoportal'] = getattr(obj, 'visible_on_geoportal', False)
data['options'] = json.loads(getattr(obj, 'options', '{}') or '{}')

data['filtered_fields'] = [item.strip() for item in obj.filtered_fields.split(',')] if hasattr(obj, 'filtered_fields') and obj.filtered_fields else None
if hasattr(obj, "get_filters"):
data['filters'] = obj.get_filters()
metadata_data = [
'date', 'language', 'category.name', 'information', 'provider_name', 'provider_web', 'provider_email',
'summary', 'bbox'
]
metadata_data_keys = [
'date', 'language', 'category', 'information', 'provider_name', 'provider_web', 'provider_email',
'summary', 'bbox'
]
metadata = {}
for k, x in zip(metadata_data_keys, metadata_data):
metadata[k] = get_value(obj, 'metadata.%s' % x)
data['metadata'] = metadata
return data


def prepare_children(obj):
children = []
service = {
'title': obj.title or obj.name,
'description': obj.description,
'group': False,
'choose_individual_layers': obj.choose_individual_layers if hasattr(obj, 'choose_individual_layers') else None,
'layers': obj.layers
}
if obj.tilecache_enabled:
url = '%s{z}/{x}/{y}.png' % reverse('qgisserver-tilecache', args=(obj.name,))
url = url_slash_join(settings.GISCUBE_URL, url)
service.update({
'type': 'TMS',
'url': url,
})
if obj.tilecache_bbox:
service.update({ 'bbox': obj.tilecache_bbox })
else:
url = url_slash_join(settings.GISCUBE_URL, '/qgisserver/services/%s' % obj.name)
service.update({
'type': 'WMS',
'url': url,
'layers': obj.default_layer or '',
'projection': '3857',
'giscube': {
'single_image': obj.wms_single_image,
'getfeatureinfo_support': obj.wms_getfeatureinfo_enabled,
},
})
children.append(service)
return children
4 changes: 2 additions & 2 deletions layerserver/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ class DataBaseLayerAdmin(ResourceAdminMixin, TabsMixin, admin.ModelAdmin):
(None, {
'fields': [
'db_connection', 'table', 'pk_field', 'data_filter',
'data_filter_status', 'data_filter_error'
'data_filter_status', 'data_filter_error', 'additional_layer'
],
'classes': ('tab-data-base',),
}),
Expand Down Expand Up @@ -453,7 +453,7 @@ class DataBaseLayerAdmin(ResourceAdminMixin, TabsMixin, admin.ModelAdmin):
(None, {
'fields': [
'db_connection', 'table', 'pk_field', 'geom_field', 'srid',
'data_filter', 'data_filter_status', 'data_filter_error'
'data_filter', 'data_filter_status', 'data_filter_error', 'additional_layer'
],
'classes': ('tab-data-base',),
}),
Expand Down
20 changes: 20 additions & 0 deletions layerserver/migrations/0036_databaselayer_additional_layer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 3.2.17 on 2025-09-03 15:14

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('qgisserver', '0036_auto_20250703_1313'),
('layerserver', '0035_auto_20250703_1408'),
]

operations = [
migrations.AddField(
model_name='databaselayer',
name='additional_layer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='databaselayers', to='qgisserver.service', verbose_name='Additional layer'),
),
]
7 changes: 7 additions & 0 deletions layerserver/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from giscube.storage import OverwriteStorage
from giscube.utils import RecursionException, check_recursion, unique_service_directory

from qgisserver.models import Service

from . import model_legacy
from .fields import ImageWithThumbnailField
from .mapserver import SUPORTED_SHAPE_TYPES
Expand Down Expand Up @@ -330,6 +332,11 @@ class DataBaseLayer(BaseLayerMixin, ShapeStyleMixin, PopupMixin, TooltipMixin, C
legend = models.TextField(_('legend'), null=True, blank=True)
catalog_color = models.CharField(_('catalog color'), max_length=50, null=True, blank=True)

additional_layer = models.ForeignKey(
Service, null=True, blank=True, on_delete=models.PROTECT,
related_name='databaselayers', verbose_name='Additional layer'
)

def get_model_field(self, field_name):
if not hasattr(self, '_model_fields'):
with model_legacy.ModelFactory(self, exclude_enabled=False) as LayerModel:
Expand Down
21 changes: 19 additions & 2 deletions layerserver/serializers/databaselayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from rest_framework import serializers

from giscube.utils import remove_app_url, url_slash_join
from giscube.models import Category
from giscube.utils import prepare_output_data, prepare_children, remove_app_url, url_slash_join
from layerserver.model_legacy import create_dblayer_model
from layerserver.models import DataBaseLayer, DataBaseLayerReference, DBLayerGroup

Expand Down Expand Up @@ -104,6 +105,7 @@ class DBLayerDetailSerializer(serializers.ModelSerializer):
virtual_fields = DBLayerVirtualFieldSerializer(many=True, read_only=True)
references = DBLayerReferenceSerializer(many=True, read_only=True)
permissions = serializers.SerializerMethodField()
additional_layer_data = serializers.SerializerMethodField()

def get_title(self, obj):
return obj.title or obj.name
Expand Down Expand Up @@ -138,6 +140,21 @@ def get_permissions(self, layer):
permission['delete'] = group_permission.can_delete

return permission

def prepare_additional_layer_children(self, obj):
children = prepare_children(obj)
return children

def get_additional_layer_data(self, obj):
if obj.additional_layer:
data = prepare_output_data(obj.additional_layer)
data['children'] = self.prepare_additional_layer_children(obj.additional_layer)
data['catalog'] = (obj.additional_layer.category.title or '').split(Category.SEPARATOR) if obj.additional_layer.category else []
data['options']['single_image'] = getattr(obj.additional_layer, 'wms_single_image', False)
data['options']['getfeatureinfo_support'] = getattr(obj.additional_layer, 'wms_getfeatureinfo_enabled', False)
data['title'] = obj.additional_layer.title or obj.additional_layer.name
return data
return None

def format_options_json(self, obj, data):
return data.update({
Expand Down Expand Up @@ -201,4 +218,4 @@ def to_representation(self, obj):
class Meta:
model = DataBaseLayer
fields = ['name', 'title', 'description', 'keywords', 'pk_field', 'geom_field', 'fields', 'virtual_fields',
'references', 'permissions']
'references', 'permissions', 'additional_layer_data']
36 changes: 2 additions & 34 deletions qgisserver/giscube_search_indexes.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,15 @@
from django.conf import settings
from django.urls import reverse

from geoportal.indexes_mixin import GeoportalSearchIndexMixin
from giscube.giscube_search_indexes_mixins import ResourcesIndexMixin
from giscube.indexes_mixin import PermissionIndexMixin
from giscube.utils import url_slash_join
from giscube.utils import prepare_children

from .models import Service


class ServiceSearch(ResourcesIndexMixin, PermissionIndexMixin, GeoportalSearchIndexMixin):

def prepare_children(self, obj):
children = []
service = {
'title': obj.title or obj.name,
'description': obj.description,
'group': False,
'choose_individual_layers': obj.choose_individual_layers if hasattr(obj, 'choose_individual_layers') else None,
'layers': obj.layers
}
if obj.tilecache_enabled:
url = '%s{z}/{x}/{y}.png' % reverse('qgisserver-tilecache', args=(obj.name,))
url = url_slash_join(settings.GISCUBE_URL, url)
service.update({
'type': 'TMS',
'url': url,
})
if obj.tilecache_bbox:
service.update({ 'bbox': obj.tilecache_bbox })
else:
url = url_slash_join(settings.GISCUBE_URL, '/qgisserver/services/%s' % obj.name)
service.update({
'type': 'WMS',
'url': url,
'layers': obj.default_layer or '',
'projection': '3857',
'giscube': {
'single_image': obj.wms_single_image,
'getfeatureinfo_support': obj.wms_getfeatureinfo_enabled,
},
})
children.append(service)
children = prepare_children(obj)
return children + super().prepare_children(obj)

def prepare_output_data(self, obj):
Expand Down