예제 #1
0
 def _get_cascaded_layer_fields(self, geoserver_resource):
     name = geoserver_resource.name
     workspace = geoserver_resource.workspace.name if hasattr(
         geoserver_resource, 'workspace') else None
     store = geoserver_resource.store if hasattr(geoserver_resource,
                                                 'store') else None
     bbox = utils.decimal_encode(geoserver_resource.native_bbox) if hasattr(geoserver_resource, 'native_bbox') else \
     utils.decimal_encode(geoserver_resource.boundingBox)
     return {
         "name":
         name,
         "workspace":
         workspace or "remoteWorkspace",
         "store":
         store.name if store and hasattr(store, 'name') else self.name,
         "typename":
         "{}:{}".format(workspace, name) if workspace not in name else name,
         "alternate":
         "{}:{}".format(workspace, name) if workspace not in name else name,
         "storeType":
         "remoteStore",
         "title":
         geoserver_resource.title,
         "abstract":
         geoserver_resource.abstract,
         "bbox_polygon":
         BBOXHelper.from_xy([bbox[0], bbox[2], bbox[1],
                             bbox[3]]).as_polygon(),
         "srid":
         bbox[4] if len(bbox) > 4 else "EPSG:4326",
     }
예제 #2
0
 def _get_indexed_layer_fields(self, layer_meta):
     bbox = utils.decimal_encode(layer_meta.boundingBox)
     return {
         "name":
         layer_meta.name,
         "store":
         self.name,
         "storeType":
         "remoteStore",
         "workspace":
         "remoteWorkspace",
         "typename":
         layer_meta.name,
         "alternate":
         layer_meta.name,
         "title":
         layer_meta.title,
         "abstract":
         layer_meta.abstract,
         "bbox_polygon":
         BBOXHelper.from_xy([bbox[0], bbox[2], bbox[1],
                             bbox[3]]).as_polygon(),
         "srid":
         bbox[4] if len(bbox) > 4 else "EPSG:4326",
         "keywords": [keyword[:100] for keyword in layer_meta.keywords],
     }
예제 #3
0
 def _get_indexed_dataset_fields(self, dataset_meta):
     bbox = utils.decimal_encode(dataset_meta.boundingBox)
     if len(bbox) < 4:
         raise RuntimeError(f"Resource BBOX is not valid: {bbox}")
     return {
         "name":
         dataset_meta.name,
         "store":
         self.name,
         "subtype":
         "remote",
         "workspace":
         "remoteWorkspace",
         "typename":
         dataset_meta.name,
         "alternate":
         dataset_meta.name,
         "title":
         dataset_meta.title,
         "abstract":
         dataset_meta.abstract,
         "bbox_polygon":
         BBOXHelper.from_xy([bbox[0], bbox[2], bbox[1],
                             bbox[3]]).as_polygon(),
         "srid":
         bbox[4] if len(bbox) > 4 else "EPSG:4326",
         "keywords": [keyword[:100] for keyword in dataset_meta.keywords],
     }
예제 #4
0
 def _get_indexed_layer_fields(self, layer_meta):
     srs = f"EPSG:{layer_meta.extent.spatialReference.wkid}"
     bbox = utils.decimal_encode([
         layer_meta.extent.xmin, layer_meta.extent.ymin,
         layer_meta.extent.xmax, layer_meta.extent.ymax
     ])
     typename = slugify(
         f"{layer_meta.id}-{''.join(c for c in layer_meta.title if ord(c) < 128)}"
     )
     return {
         "name":
         layer_meta.title,
         "store":
         self.name,
         "storeType":
         "remoteStore",
         "workspace":
         "remoteWorkspace",
         "typename":
         typename,
         "alternate":
         f"{slugify(self.url)}:{layer_meta.id}",
         "title":
         layer_meta.title,
         "abstract":
         layer_meta.abstract,
         "bbox_polygon":
         BBOXHelper.from_xy([bbox[0], bbox[2], bbox[1],
                             bbox[3]]).as_polygon(),
         "srid":
         srs,
         "keywords": ['ESRI', 'ArcGIS REST MapServer', layer_meta.title],
     }
예제 #5
0
    def form_valid(self, form):
        """
        If the form is valid, save the associated model.
        """
        doc_form = form.cleaned_data

        file = doc_form.pop('doc_file', None)
        if file:
            tempdir = tempfile.mkdtemp(dir=settings.STATIC_ROOT)
            dirname = os.path.basename(tempdir)
            filepath = storage_manager.save(f"{dirname}/{file.name}", file)
            storage_path = storage_manager.path(filepath)
            self.object = resource_manager.create(
                None,
                resource_type=Document,
                defaults=dict(owner=self.request.user,
                              doc_url=doc_form.pop('doc_url', None),
                              title=doc_form.pop('title', file.name),
                              files=[storage_path]))
            if tempdir != os.path.dirname(storage_path):
                shutil.rmtree(tempdir, ignore_errors=True)
        else:
            self.object = resource_manager.create(
                None,
                resource_type=Document,
                defaults=dict(owner=self.request.user,
                              doc_url=doc_form.pop('doc_url', None),
                              title=doc_form.pop('title', None)))

        if settings.ADMIN_MODERATE_UPLOADS:
            self.object.is_approved = False
        if settings.RESOURCE_PUBLISHING:
            self.object.is_published = False

        resource_manager.set_permissions(
            None,
            instance=self.object,
            permissions=form.cleaned_data["permissions"],
            created=True)

        abstract = None
        date = None
        regions = []
        keywords = []
        bbox = None
        url = hookset.document_detail_url(self.object)

        out = {'success': False}

        if getattr(settings, 'EXIF_ENABLED', False):
            try:
                from geonode.documents.exif.utils import exif_extract_metadata_doc
                exif_metadata = exif_extract_metadata_doc(self.object)
                if exif_metadata:
                    date = exif_metadata.get('date', None)
                    keywords.extend(exif_metadata.get('keywords', []))
                    bbox = exif_metadata.get('bbox', None)
                    abstract = exif_metadata.get('abstract', None)
            except Exception:
                logger.debug("Exif extraction failed.")

        resource_manager.update(
            self.object.uuid,
            instance=self.object,
            keywords=keywords,
            regions=regions,
            vals=dict(abstract=abstract,
                      date=date,
                      date_type="Creation",
                      bbox_polygon=BBOXHelper.from_xy(bbox).as_polygon()
                      if bbox else None),
            notify=True)
        resource_manager.set_thumbnail(self.object.uuid,
                                       instance=self.object,
                                       overwrite=False)

        register_event(self.request, EventType.EVENT_UPLOAD, self.object)

        if self.request.GET.get('no__redirect', False):
            out['success'] = True
            out['url'] = url
            if out['success']:
                status_code = 200
            else:
                status_code = 400
            return HttpResponse(json.dumps(out),
                                content_type='application/json',
                                status=status_code)
        else:
            return HttpResponseRedirect(url)
예제 #6
0
def file_upload(filename,
                layer=None,
                gtype=None,
                name=None,
                user=None,
                title=None,
                abstract=None,
                license=None,
                category=None,
                keywords=None,
                regions=None,
                date=None,
                skip=True,
                overwrite=False,
                charset='UTF-8',
                is_approved=True,
                is_published=True,
                metadata_uploaded_preserve=False,
                metadata_upload_form=False):
    """Saves a layer in GeoNode asking as little information as possible.
       Only filename is required, user and title are optional.

    :return: Uploaded layer
    :rtype: Layer
    """
    if keywords is None:
        keywords = []
    if regions is None:
        regions = []

    # Get a valid user
    theuser = get_valid_user(user)

    # Create a new upload session
    if layer:
        latest_uploads = UploadSession.objects.filter(
            resource=layer).order_by('-date')
        if latest_uploads.count() > 1:
            upload_session = latest_uploads.first()
        else:
            upload_session, _created = UploadSession.objects.get_or_create(
                resource=layer)
        upload_session.user = theuser
        upload_session.layerfile_set.all().delete()
    else:
        upload_session = UploadSession.objects.create(user=theuser)

    # Get all the files uploaded with the layer
    if os.path.exists(filename):
        files = get_files(filename)
    else:
        raise Exception(
            _("You are attempting to replace a vector layer with an unknown format."
              ))

    # We are going to replace an existing Layer...
    if layer and overwrite:
        validate_input_source(layer,
                              filename,
                              files,
                              gtype,
                              action_type='replace')

    # Set a default title that looks nice ...
    if title is None:
        basename = os.path.splitext(os.path.basename(filename))[0]
        title = basename.title().replace('_', ' ')

    # Create a name from the title if it is not passed.
    if name is None:
        name = slugify(title).replace('-', '_')
    elif not overwrite:
        name = slugify(name)  # assert that name is slugified

    if license is not None:
        licenses = License.objects.filter(
            Q(name__iexact=license) | Q(abbreviation__iexact=license)
            | Q(url__iexact=license) | Q(description__iexact=license))
        if len(licenses) == 1:
            license = licenses[0]
        else:
            license = None

    if category is not None:
        try:
            categories = TopicCategory.objects.filter(
                Q(identifier__iexact=category)
                | Q(gn_description__iexact=category))
            if len(categories) == 1:
                category = categories[0]
            else:
                category = None
        except Exception:
            pass

    # Generate a name that is not taken if overwrite is False.
    valid_name = get_valid_layer_name(name, overwrite)

    # Add them to the upload session (new file fields are created).
    assigned_name = None
    for type_name, fn in files.items():
        with open(fn, 'rb') as f:
            upload_session.layerfile_set.create(
                name=type_name,
                file=File(f,
                          name=f'{assigned_name or valid_name}.{type_name}'))
            # save the system assigned name for the remaining files
            if not assigned_name:
                the_file = upload_session.layerfile_set.all()[0].file.name
                assigned_name = os.path.splitext(os.path.basename(the_file))[0]

    # Get a bounding box
    *bbox, srid = get_bbox(filename)
    bbox_polygon = BBOXHelper.from_xy(bbox).as_polygon()

    if srid:
        srid_url = f"http://www.spatialreference.org/ref/{srid.replace(':', '/').lower()}/"  # noqa
        bbox_polygon.srid = int(srid.split(':')[1])

    # by default, if RESOURCE_PUBLISHING=True then layer.is_published
    # must be set to False
    if not overwrite:
        if settings.RESOURCE_PUBLISHING:
            is_published = False
        if settings.ADMIN_MODERATE_UPLOADS:
            is_approved = False

    defaults = {
        'upload_session': upload_session,
        'title': title,
        'abstract': abstract,
        'owner': user,
        'charset': charset,
        'bbox_polygon': bbox_polygon,
        'srid': 'EPSG:4326',
        'is_approved': is_approved,
        'is_published': is_published,
        'license': license,
        'category': category
    }

    # set metadata
    if 'xml' in files:
        with open(files['xml']) as f:
            xml_file = f.read()

        defaults['metadata_uploaded'] = True
        defaults['metadata_uploaded_preserve'] = metadata_uploaded_preserve

        # get model properties from XML
        identifier, vals, regions, keywords = set_metadata(xml_file)

        if defaults['metadata_uploaded_preserve']:
            defaults['metadata_xml'] = xml_file

        if identifier:
            if ResourceBase.objects.filter(uuid=identifier).count():
                logger.error(
                    "The UUID identifier from the XML Metadata is already in use in this system."
                )
                raise GeoNodeException(
                    _("The UUID identifier from the XML Metadata is already in use in this system."
                      ))
            else:
                defaults['uuid'] = identifier

        for key, value in vals.items():
            if key == 'spatial_representation_type':
                value = SpatialRepresentationType(identifier=value)
            elif key == 'topic_category':
                value, created = TopicCategory.objects.get_or_create(
                    identifier=value,
                    defaults={
                        'description': '',
                        'gn_description': value
                    })
                key = 'category'
            defaults[key] = value

    regions_resolved, regions_unresolved = resolve_regions(regions)
    if keywords and regions_unresolved:
        keywords.extend(convert_keyword(regions_unresolved))

    # If it is a vector file, create the layer in postgis.
    if is_vector(filename):
        defaults['storeType'] = 'dataStore'

    # If it is a raster file, get the resolution.
    if is_raster(filename):
        defaults['storeType'] = 'coverageStore'

    # Create a Django object.
    created = False
    layer = None
    try:
        with transaction.atomic():
            if overwrite:
                try:
                    layer = Layer.objects.get(name=valid_name)
                except Layer.DoesNotExist:
                    layer = None
            if not layer:
                if not metadata_upload_form:
                    layer = Layer.objects.filter(
                        name=valid_name,
                        workspace=settings.DEFAULT_WORKSPACE).first()
                    if not layer:
                        layer = Layer.objects.create(
                            name=valid_name,
                            workspace=settings.DEFAULT_WORKSPACE)
                        created = True
                elif identifier:
                    layer = Layer.objects.filter(uuid=identifier).first()
                    if not layer:
                        layer = Layer.objects.create(uuid=identifier)
                        created = True
    except IntegrityError:
        raise

    # Delete the old layers if overwrite is true
    # and the layer was not just created
    # process the layer again after that by
    # doing a layer.save()
    if not created and overwrite:
        # update with new information
        defaults['title'] = defaults.get('title', None) or layer.title
        defaults['abstract'] = defaults.get('abstract', None) or layer.abstract
        defaults['bbox_polygon'] = defaults.get('bbox_polygon',
                                                None) or layer.bbox_polygon
        defaults['ll_bbox_polygon'] = defaults.get(
            'll_bbox_polygon', None) or layer.ll_bbox_polygon
        defaults['is_approved'] = defaults.get(
            'is_approved', is_approved) or layer.is_approved
        defaults['is_published'] = defaults.get(
            'is_published', is_published) or layer.is_published
        defaults['license'] = defaults.get('license', None) or layer.license
        defaults['category'] = defaults.get('category', None) or layer.category

        if upload_session:
            if layer.upload_session:
                layer.upload_session.date = upload_session.date
                layer.upload_session.user = upload_session.user
                layer.upload_session.error = upload_session.error
                layer.upload_session.traceback = upload_session.traceback
                layer.upload_session.context = upload_session.context
                upload_session = layer.upload_session
            else:
                layer.upload_session = upload_session
    if upload_session:
        defaults['upload_session'] = upload_session
        upload_session.resource = layer
        upload_session.processed = False
        upload_session.save()

    layer = KeywordHandler(layer, keywords).set_keywords()

    # Assign the regions (needs to be done after saving)
    regions_resolved = list(set(regions_resolved))
    if regions_resolved:
        if len(regions_resolved) > 0:
            if not layer.regions:
                layer.regions = regions_resolved
            else:
                layer.regions.clear()
                layer.regions.add(*regions_resolved)

    # Assign and save the charset using the Layer class' object (layer)
    if charset != 'UTF-8':
        layer.charset = charset

    if not defaults.get('title', title):
        defaults['title'] = layer.title or layer.name
    if not defaults.get('abstract', abstract):
        defaults['abstract'] = layer.abstract or ''

    to_update = {}
    to_update['upload_session'] = defaults.pop('upload_session',
                                               layer.upload_session)
    to_update['storeType'] = defaults.pop('storeType', layer.storeType)
    to_update['charset'] = defaults.pop('charset', layer.charset)
    to_update.update(defaults)
    if defaults.get('date', date) is not None:
        to_update['date'] = defaults.get(
            'date',
            datetime.strptime(date, '%Y-%m-%d %H:%M:%S') if date else None)

    # Update ResourceBase
    if not to_update:
        pass
    else:
        try:
            with transaction.atomic():
                if 'spatial_representation_type' in defaults:
                    _spatial_ref_type = defaults.pop(
                        'spatial_representation_type')
                    _spatial_ref_type.save()
                    defaults['spatial_representation_type'] = _spatial_ref_type
                ResourceBase.objects.filter(
                    id=layer.resourcebase_ptr.id).update(**defaults)
                Layer.objects.filter(id=layer.id).update(**to_update)

                # Refresh from DB
                layer.refresh_from_db()

                # Pass the parameter overwrite to tell whether the
                # geoserver_post_save_signal should upload the new file or not
                layer.overwrite = overwrite

                # Blank out the store if overwrite is true.
                # geoserver_post_save_signal should upload the new file if needed
                layer.store = '' if overwrite else layer.store
        except IntegrityError:
            raise
    try:
        with transaction.atomic():
            layer.save(notify=True)
    except IntegrityError:
        raise
    return layer
예제 #7
0
    def form_valid(self, form):
        """
        If the form is valid, save the associated model.
        """
        self.object = form.save(commit=False)
        self.object.owner = self.request.user

        if settings.ADMIN_MODERATE_UPLOADS:
            self.object.is_approved = False
        if settings.RESOURCE_PUBLISHING:
            self.object.is_published = False
        self.object.save()
        form.save_many2many()
        self.object.set_permissions(form.cleaned_data['permissions'])

        abstract = None
        date = None
        regions = []
        keywords = []
        bbox = None

        out = {'success': False}

        if getattr(settings, 'EXIF_ENABLED', False):
            try:
                from geonode.documents.exif.utils import exif_extract_metadata_doc
                exif_metadata = exif_extract_metadata_doc(self.object)
                if exif_metadata:
                    date = exif_metadata.get('date', None)
                    keywords.extend(exif_metadata.get('keywords', []))
                    bbox = exif_metadata.get('bbox', None)
                    abstract = exif_metadata.get('abstract', None)
            except Exception:
                logger.error("Exif extraction failed.")

        if abstract:
            self.object.abstract = abstract

        if date:
            self.object.date = date
            self.object.date_type = "Creation"

        if len(regions) > 0:
            self.object.regions.add(*regions)

        if len(keywords) > 0:
            self.object.keywords.add(*keywords)

        if bbox:
            bbox = BBOXHelper.from_xy(bbox)
            self.object.bbox_polygon = bbox.as_polygon()

        self.object.save(notify=True)
        register_event(self.request, EventType.EVENT_UPLOAD, self.object)

        if self.request.GET.get('no__redirect', False):
            out['success'] = True
            out['url'] = reverse('document_detail', args=(self.object.id, ))
            if out['success']:
                status_code = 200
            else:
                status_code = 400
            return HttpResponse(json.dumps(out),
                                content_type='application/json',
                                status=status_code)
        else:
            return HttpResponseRedirect(
                reverse('document_detail', args=(self.object.id, )))
    def set_geonode_map(self,
                        caller,
                        serializer,
                        map_obj=None,
                        data=None,
                        attributes=None):
        def decode_base64(data):
            """Decode base64, padding being optional.

            :param data: Base64 data as an ASCII byte string
            :returns: The decoded byte string.

            """
            _thumbnail_format = 'png'
            _invalid_padding = data.find(';base64,')
            if _invalid_padding:
                _thumbnail_format = data[data.find('image/') +
                                         len('image/'):_invalid_padding]
                data = data[_invalid_padding + len(';base64,'):]
            missing_padding = len(data) % 4
            if missing_padding != 0:
                data += b'=' * (4 - missing_padding)
            return (base64.b64decode(data), _thumbnail_format)

        _map_name = None
        _map_title = None
        _map_abstract = None
        _map_thumbnail = None
        _map_thumbnail_format = 'png'
        if attributes:
            for _a in attributes:
                if _a['name'] == 'name' and 'value' in _a:
                    _map_name = _a['value']
                if _a['name'] == 'title' and 'value' in _a:
                    _map_title = _a['value']
                if _a['name'] == 'abstract' and 'value' in _a:
                    _map_abstract = _a['value']
                if 'thumb' in _a['name'] and 'value' in _a:
                    try:
                        (_map_thumbnail,
                         _map_thumbnail_format) = decode_base64(_a['value'])
                    except Exception:
                        if _a['value']:
                            _map_thumbnail = _a['value']
                            _map_thumbnail_format = 'link'
        elif map_obj:
            _map_title = map_obj.title
            _map_abstract = map_obj.abstract

        _map_name = _map_name or None
        if not _map_name and 'name' in serializer.validated_data:
            _map_name = serializer.validated_data['name']
        _map_title = _map_title or _map_name
        _map_abstract = _map_abstract or ""
        if data:
            try:
                _map_conf = dict(data)
                _map_conf["about"] = {
                    "name": _map_name,
                    "title": _map_title,
                    "abstract": _map_abstract
                }
                _map_conf['sources'] = {}
                from geonode.layers.views import layer_detail
                _map_obj = data.pop('map', None)
                if _map_obj:
                    _map_bbox = []
                    for _lyr in _map_obj['layers']:
                        _lyr_context = {}
                        _lyr_store = _lyr['store'] if 'store' in _lyr else None
                        if not _lyr_store:
                            try:
                                _url = urlparse(_lyr['catalogURL'])
                                _lyr_store = Layer.objects.get(
                                    uuid=parse_qs(_url.query)['id'][0]).store
                            except Exception:
                                try:
                                    _lyr_store = Layer.objects.get(
                                        alternate=_lyr['name'],
                                        remote_service__base_url=_lyr['url']
                                    ).store
                                except Exception:
                                    _lyr_store = None

                        _lyr_name = "%s:%s" % (
                            _lyr_store,
                            _lyr['name']) if _lyr_store else _lyr['name']
                        try:
                            # Retrieve the Layer Params back from GeoNode
                            _gn_layer = layer_detail(caller.request, _lyr_name)
                            if _gn_layer and _gn_layer.context_data:
                                _context_data = json.loads(
                                    _gn_layer.context_data['viewer'])
                                for _gn_layer_ctx in _context_data['map'][
                                        'layers']:
                                    if 'name' in _gn_layer_ctx and _gn_layer_ctx[
                                            'name'] == _lyr['name']:
                                        _lyr['store'] = _lyr_store
                                        if 'style' in _lyr:
                                            _lyr_context['style'] = _lyr[
                                                'style']
                                        _lyr_context = _gn_layer_ctx
                                        _src_idx = _lyr_context['source']
                                        _map_conf['sources'][
                                            _src_idx] = _context_data[
                                                'sources'][_src_idx]
                        except Http404:
                            tb = traceback.format_exc()
                            logger.debug(tb)
                        except Exception:
                            raise
                        # Store ms2 layer idq
                        if "id" in _lyr and _lyr["id"]:
                            _lyr['extraParams'] = {"msId": _lyr["id"]}

                        # Store the Capabilities Document into the Layer Params of GeoNode
                        if _lyr_context:
                            if 'ftInfoTemplate' in _lyr_context:
                                _lyr['ftInfoTemplate'] = _lyr_context[
                                    'ftInfoTemplate']
                            if 'getFeatureInfo' in _lyr_context:
                                _lyr['getFeatureInfo'] = _lyr_context[
                                    'getFeatureInfo']
                            if 'capability' in _lyr_context:
                                _lyr['capability'] = _lyr_context['capability']
                                if 'bbox' in _lyr_context['capability']:
                                    _lyr_bbox = _lyr_context['capability'][
                                        'bbox']
                                    if _map_obj['projection'] in _lyr_bbox:
                                        x0 = _lyr_bbox[
                                            _map_obj['projection']]['bbox'][0]
                                        x1 = _lyr_bbox[
                                            _map_obj['projection']]['bbox'][2]
                                        y0 = _lyr_bbox[
                                            _map_obj['projection']]['bbox'][1]
                                        y1 = _lyr_bbox[
                                            _map_obj['projection']]['bbox'][3]

                                        if len(_map_bbox) == 0:
                                            _map_bbox = [x0, x1, y0, y1]
                                        else:
                                            from geonode.utils import bbox_to_wkt
                                            from django.contrib.gis.geos import GEOSGeometry

                                            _l_wkt = bbox_to_wkt(
                                                x0,
                                                x1,
                                                y0,
                                                y1,
                                                srid=_map_obj['projection'])
                                            _m_wkt = bbox_to_wkt(
                                                _map_bbox[0],
                                                _map_bbox[2],
                                                _map_bbox[1],
                                                _map_bbox[3],
                                                srid=_map_obj['projection'])
                                            _map_srid = int(
                                                _map_obj['projection'][5:])
                                            _l_poly = GEOSGeometry(
                                                _l_wkt, srid=_map_srid)
                                            _m_poly = GEOSGeometry(
                                                _m_wkt,
                                                srid=_map_srid).union(_l_poly)
                                            _map_bbox = _m_poly.extent

                            if 'source' in _lyr_context:
                                _source = _map_conf['sources'][
                                    _lyr_context['source']]
                                if 'remote' in _source and _source[
                                        'remote'] is True:
                                    _lyr['source'] = _lyr_context['source']
                        elif 'source' in _lyr:
                            _map_conf['sources'][_lyr['source']] = {}
                    event_type = None
                    if is_analytics_enabled:
                        event_type = EventType.EVENT_CHANGE

                    if not map_obj:
                        # Update Map BBox
                        if 'bbox' not in _map_obj and (not _map_bbox
                                                       or len(_map_bbox) != 4):
                            _map_bbox = _map_obj['maxExtent']
                            # Must be in the form : [x0, x1, y0, y1]
                            _map_obj['bbox'] = [
                                _map_bbox[0], _map_bbox[1], _map_bbox[2],
                                _map_bbox[3]
                            ]
                        # Create a new GeoNode Map
                        from geonode.maps.models import Map
                        map_obj = Map(title=_map_title,
                                      owner=caller.request.user,
                                      center_x=_map_obj['center']['x'],
                                      center_y=_map_obj['center']['y'],
                                      projection=_map_obj['projection'],
                                      zoom=_map_obj['zoom'],
                                      srid=_map_obj['projection'])
                        if 'bbox' in _map_obj:
                            if hasattr(map_obj, 'bbox_polygon'):
                                map_obj.bbox_polygon = BBOXHelper.from_xy(
                                    _map_obj['bbox']).as_polygon()
                            else:
                                map_obj.bbox_x0 = _map_obj['bbox'][0]
                                map_obj.bbox_y0 = _map_obj['bbox'][1]
                                map_obj.bbox_x1 = _map_obj['bbox'][2]
                                map_obj.bbox_y1 = _map_obj['bbox'][3]
                        map_obj.save()

                        if is_analytics_enabled:
                            event_type = EventType.EVENT_CREATE

                    # Dumps thumbnail from MapStore2 Interface
                    if _map_thumbnail:
                        # note: dumping a thumbnail should be performed before update_from_viewer(), to remove
                        # a race hazard. update_from_viewer() saves an existing map without a thumbnail,
                        # triggering asynchronous generation of a default thumbnail, which may overwrite uploaded thumb
                        if _map_thumbnail_format == 'link':
                            map_obj.thumbnail_url = _map_thumbnail
                        else:
                            _map_thumbnail_filename = "map-%s-thumb.%s" % (
                                map_obj.uuid, _map_thumbnail_format)
                            map_obj.save_thumbnail(_map_thumbnail_filename,
                                                   _map_thumbnail)

                    # Update GeoNode Map
                    _map_conf['map'] = _map_obj
                    map_obj.update_from_viewer(_map_conf,
                                               context={'config': _map_conf})

                    if is_analytics_enabled:
                        register_event(caller.request, event_type, map_obj)

                    serializer.validated_data['id'] = map_obj.id
                    serializer.save(user=caller.request.user)
            except Exception as e:
                tb = traceback.format_exc()
                logger.error(tb)
                raise APIException(e)
        else:
            raise APIException("Map Configuration (data) is Mandatory!")
예제 #9
0
    def set_geonode_map(self, caller, serializer, map_obj=None, data=None):

        _map_name = serializer.validated_data['title'] or map_obj.title
        _map_title = serializer.validated_data['title'] or map_obj.title
        _map_abstract = serializer.validated_data.get(
            'abstract',
            '') or '' if not hasattr(map_obj, 'abstract') else map_obj.abstract

        if data:
            try:
                data_blob = data.copy()
                _map_conf = dict(data)
                _map_conf["about"] = {
                    "name": _map_name,
                    "title": _map_title,
                    "abstract": _map_abstract
                }
                _map_conf['sources'] = {}
                from geonode.layers.views import layer_detail
                _map_obj = data.pop('map', None)
                if _map_obj:
                    _map_bbox = []
                    for _lyr in _map_obj['layers']:
                        _lyr_context = {}
                        _lyr_store = _lyr['store'] if 'store' in _lyr else None
                        if not _lyr_store:
                            try:
                                _url = urlparse(_lyr['catalogURL'])
                                _lyr_store = Layer.objects.get(
                                    uuid=parse_qs(_url.query)['id'][0]).store
                            except Exception:
                                try:
                                    _lyr_store = Layer.objects.get(
                                        alternate=_lyr['name'],
                                        remote_service__base_url=_lyr['url']
                                    ).store
                                except Exception:
                                    _lyr_store = None

                        _lyr_name = f"{_lyr_store}:{_lyr['name']}" if _lyr_store else _lyr[
                            'name']
                        try:
                            # Retrieve the Layer Params back from GeoNode
                            _gn_layer = layer_detail(caller.request, _lyr_name)
                            if _gn_layer and _gn_layer.context_data:
                                _context_data = json.loads(
                                    _gn_layer.context_data['viewer'])
                                for _gn_layer_ctx in _context_data['map'][
                                        'layers']:
                                    if 'name' in _gn_layer_ctx and _gn_layer_ctx[
                                            'name'] == _lyr['name']:
                                        _lyr['store'] = _lyr_store
                                        if 'style' in _lyr:
                                            _lyr_context['style'] = _lyr[
                                                'style']
                                            if 'capability' in _gn_layer_ctx:
                                                # Add selected style to capability in layer_params
                                                _gn_layer_ctx['capability'][
                                                    'style'] = _lyr['style']
                                        _lyr_context = _gn_layer_ctx
                                        _src_idx = _lyr_context['source']
                                        _map_conf['sources'][
                                            _src_idx] = _context_data[
                                                'sources'][_src_idx]
                        except Http404:
                            tb = traceback.format_exc()
                            logger.debug(tb)
                        except Exception:
                            raise
                        # Store ms2 layer idq
                        if "id" in _lyr and _lyr["id"]:
                            _lyr['extraParams'] = {"msId": _lyr["id"]}

                        # Store the Capabilities Document into the Layer Params of GeoNode
                        if _lyr_context:
                            if 'ftInfoTemplate' in _lyr_context:
                                _lyr['ftInfoTemplate'] = _lyr_context[
                                    'ftInfoTemplate']
                            if 'getFeatureInfo' in _lyr_context:
                                _lyr['getFeatureInfo'] = _lyr_context[
                                    'getFeatureInfo']
                            if 'capability' in _lyr_context:
                                _lyr['capability'] = _lyr_context['capability']
                                if 'bbox' in _lyr_context['capability']:
                                    _lyr_bbox = _lyr_context['capability'][
                                        'bbox']
                                    if _map_obj['projection'] in _lyr_bbox:
                                        x0 = _lyr_bbox[
                                            _map_obj['projection']]['bbox'][0]
                                        x1 = _lyr_bbox[
                                            _map_obj['projection']]['bbox'][2]
                                        y0 = _lyr_bbox[
                                            _map_obj['projection']]['bbox'][1]
                                        y1 = _lyr_bbox[
                                            _map_obj['projection']]['bbox'][3]

                                        if len(_map_bbox) == 0:
                                            _map_bbox = [x0, x1, y0, y1]
                                        else:
                                            from geonode.utils import bbox_to_wkt
                                            from django.contrib.gis.geos import GEOSGeometry

                                            _l_wkt = bbox_to_wkt(
                                                x0,
                                                x1,
                                                y0,
                                                y1,
                                                srid=_map_obj['projection'])
                                            _m_wkt = bbox_to_wkt(
                                                _map_bbox[0],
                                                _map_bbox[2],
                                                _map_bbox[1],
                                                _map_bbox[3],
                                                srid=_map_obj['projection'])
                                            _map_srid = int(
                                                _map_obj['projection'][5:])
                                            _l_poly = GEOSGeometry(
                                                _l_wkt, srid=_map_srid)
                                            _m_poly = GEOSGeometry(
                                                _m_wkt,
                                                srid=_map_srid).union(_l_poly)
                                            _map_bbox = _m_poly.extent

                            if 'source' in _lyr_context:
                                _source = _map_conf['sources'][
                                    _lyr_context['source']]
                                if 'remote' in _source and _source[
                                        'remote'] is True:
                                    _lyr['source'] = _lyr_context['source']
                        elif 'source' in _lyr:
                            _map_conf['sources'][_lyr['source']] = {}
                    event_type = None
                    if is_analytics_enabled:
                        event_type = EventType.EVENT_CHANGE

                    if not map_obj:
                        # Create a new GeoNode Map
                        from geonode.maps.models import Map
                        map_obj = Map(title=_map_title,
                                      abstract=_map_abstract,
                                      owner=caller.request.user,
                                      center_x=_map_obj['center']['x'],
                                      center_y=_map_obj['center']['y'],
                                      projection=_map_obj['projection'],
                                      zoom=_map_obj['zoom'],
                                      srid=_map_obj['projection'],
                                      resource_type="map")

                        if 'bbox' in _map_obj:
                            if hasattr(map_obj, 'bbox_polygon'):
                                map_obj.bbox_polygon = BBOXHelper.from_xy(
                                    _map_obj['bbox']).as_polygon()
                            else:
                                map_obj.bbox_x0 = _map_obj['bbox'][0]
                                map_obj.bbox_y0 = _map_obj['bbox'][1]
                                map_obj.bbox_x1 = _map_obj['bbox'][2]
                                map_obj.bbox_y1 = _map_obj['bbox'][3]
                        elif hasattr(map_obj, 'bbox_polygon'
                                     ) and map_obj.bbox_polygon is None:
                            # set the bbox_polygon to the obj and then to serializer instance
                            map_obj.set_bounds_from_center_and_zoom(
                                _map_obj['center']['x'],
                                _map_obj['center']['y'], _map_obj['zoom'])

                        if is_analytics_enabled:
                            event_type = EventType.EVENT_CREATE
                    else:
                        map_obj.title = _map_title
                        map_obj.abstract = _map_abstract

                    if not map_obj.uuid:
                        map_obj.uuid = str(uuid4())

                    map_obj.blob = data_blob
                    # Update GeoNode Map
                    _map_conf['map'] = _map_obj

                    if is_analytics_enabled:
                        register_event(caller.request, event_type, map_obj)

                    serializer.instance = map_obj
                    serializer.save()

                    serializer.instance.update_from_viewer(
                        _map_conf, context={'config': _map_conf})
                    return serializer

            except Exception as e:
                tb = traceback.format_exc()
                logger.error(tb)
                raise APIException(e)
        else:
            raise APIException("Map Configuration (data) is Mandatory!")