Exemplo n.º 1
0
 def get_url_internal_wfs(
     self, ogc_server: main.OGCServer, errors: Set[str]
 ) -> Tuple[Optional[Url], Optional[Url], Optional[Url]]:
     # required to do every time to validate the url.
     if ogc_server.auth != main.OGCSERVER_AUTH_NOAUTH:
         url: Optional[Url] = Url(
             self.request.route_url("mapserverproxy", _query={"ogcserver": ogc_server.name})
         )
         url_wfs: Optional[Url] = url
         url_internal_wfs = get_url2(
             f"The OGC server (WFS) '{ogc_server.name}'",
             ogc_server.url_wfs or ogc_server.url,
             self.request,
             errors=errors,
         )
     else:
         url = get_url2(f"The OGC server '{ogc_server.name}'", ogc_server.url, self.request, errors=errors)
         url_wfs = (
             get_url2(
                 f"The OGC server (WFS) '{ogc_server.name}'",
                 ogc_server.url_wfs,
                 self.request,
                 errors=errors,
             )
             if ogc_server.url_wfs is not None
             else url
         )
         url_internal_wfs = url_wfs
     return url_internal_wfs, url, url_wfs
Exemplo n.º 2
0
 def url_wfs_description(self,
                         request: pyramid.request.Request) -> Optional[str]:
     if not self.url_wfs:
         return self.url_description(request)
     errors: Set[str] = set()
     url = get_url2(self.name, self.url_wfs, request, errors)
     return url.url() if url else "\n".join(errors)
Exemplo n.º 3
0
 def _get_wms_url(self, errors: Set[str]) -> Optional[Url]:
     ogc_server = self.ogc_server
     url = get_url2(f"The OGC server '{ogc_server.name}'", ogc_server.url,
                    self.request, errors)
     if errors:
         LOG.error("\n".join(errors))
     return url
Exemplo n.º 4
0
    def _themes(self,
                interface: str = "desktop",
                filter_themes: bool = True,
                min_levels: int = 1) -> Tuple[List[Dict[str, Any]], Set[str]]:
        """
        This function returns theme information for the role identified
        by ``role_id``.
        """
        self._load_tree_items()
        errors = set()
        layers = self._layers(interface)

        themes = models.DBSession.query(main.Theme)
        themes = themes.filter(main.Theme.public.is_(True))
        auth_themes = models.DBSession.query(main.Theme)
        auth_themes = auth_themes.filter(main.Theme.public.is_(False))
        auth_themes = auth_themes.join(main.Theme.restricted_roles)
        auth_themes = auth_themes.filter(
            main.Role.id.in_(get_roles_id(self.request)))

        themes = themes.union(auth_themes)

        themes = themes.order_by(main.Theme.ordering.asc())

        if filter_themes and interface is not None:
            themes = themes.join(main.Theme.interfaces)
            themes = themes.filter(main.Interface.name == interface)

        export_themes = []
        for theme in themes.all():
            if re.search("[/?#]", theme.name):
                errors.add("The theme has an unsupported name '{}'.".format(
                    theme.name))
                continue

            children, children_errors = self._get_children(
                theme, layers, min_levels)
            errors |= children_errors

            # Test if the theme is visible for the current user
            if children:
                icon = (get_url2("The Theme '{}'".format(theme.name),
                                 theme.icon, self.request, errors)
                        if theme.icon is not None and theme.icon else
                        self.request.static_url(
                            "/etc/geomapfish/static/images/blank.png"))

                theme_theme = {
                    "id": theme.id,
                    "name": theme.name,
                    "icon": icon,
                    "children": children,
                    "functionalities": self._get_functionalities(theme),
                    "metadata": self._get_metadatas(theme, errors),
                }
                export_themes.append(theme_theme)

        return export_themes, errors
Exemplo n.º 5
0
 def _get_wfs_url(self, errors: Set[str]) -> Optional[Url]:
     ogc_server = self.ogc_server
     url = get_url2(
         "The OGC server (WFS) '{}'".format(ogc_server.name),
         ogc_server.url_wfs or ogc_server.url,
         self.request,
         errors,
     )
     if errors:
         LOG.error("\n".join(errors))
     return url
Exemplo n.º 6
0
    def _fill_wmts(self, layer_theme: Dict[str, Any], layer: main.Layer, errors: Set[str]) -> None:
        url = get_url2(f"The WMTS layer '{layer.name}'", layer.url, self.request, errors=errors)
        layer_theme["url"] = url.url() if url is not None else None

        if layer.style:
            layer_theme["style"] = layer.style
        if layer.matrix_set:
            layer_theme["matrixSet"] = layer.matrix_set

        layer_theme["layer"] = layer.layer
        layer_theme["imageType"] = layer.image_type
Exemplo n.º 7
0
def get_ogc_server_wfs_url_ids(request: pyramid.request.Request) -> Dict[str, List[int]]:
    """Get the OGCServer ids mapped on the WFS URL."""
    from c2cgeoportal_commons.models import DBSession  # pylint: disable=import-outside-toplevel
    from c2cgeoportal_commons.models.main import OGCServer  # pylint: disable=import-outside-toplevel

    errors: Set[str] = set()
    servers: Dict[str, List[int]] = {}
    for ogc_server in DBSession.query(OGCServer).all():
        url = get_url2(ogc_server.name, ogc_server.url_wfs or ogc_server.url, request, errors)
        if url is not None:
            servers.setdefault(url.url(), []).append(ogc_server.id)
    return servers
Exemplo n.º 8
0
    def _fill_wmts(self, layer_theme: Dict[str, Any], layer: main.Layer,
                   errors: Set[str]) -> None:
        layer_theme["url"] = get_url2("The WMTS layer '{}'".format(layer.name),
                                      layer.url,
                                      self.request,
                                      errors=errors)

        if layer.style:
            layer_theme["style"] = layer.style
        if layer.matrix_set:
            layer_theme["matrixSet"] = layer.matrix_set

        layer_theme["layer"] = layer.layer
        layer_theme["imageType"] = layer.image_type
Exemplo n.º 9
0
    def wms_capabilities(self) -> bytes:
        errors: Set[str] = set()
        url = get_url2(
            "The OGC server '{}'".format(self._ogc_server.name),
            self._ogc_server.url,
            self._request,
            errors,
        )
        if url is None:
            raise Exception("\n".join(errors))

        # Add functionality params
        # sparams = get_mapserver_substitution_params(self.request)
        # url.add_query(url, sparams)

        url.add_query(
            {
                "SERVICE": "WMS",
                "VERSION": "1.1.1",
                "REQUEST": "GetCapabilities",
                "ROLE_ID": "0",
                "USER_ID": "0",
            },
        )

        self._logger.info("Get WMS GetCapabilities from: %s", url)

        headers = {}

        # Add headers for Geoserver
        if self._ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER:
            headers["sec-username"] = "******"
            headers["sec-roles"] = "root"

        response = requests.get(url.url(), headers=headers, timeout=300)
        self._logger.info("Got response %s in %.1fs.", response.status_code, response.elapsed.total_seconds())
        response.raise_for_status()

        # With WMS 1.3 it returns text/xml also in case of error :-(
        if response.headers.get("Content-Type", "").split(";")[0].strip() not in [
            "application/vnd.ogc.wms_xml",
            "text/xml",
        ]:
            raise Exception(
                "GetCapabilities from URL {} returns a wrong Content-Type: {}\n{}".format(
                    url, response.headers.get("Content-Type", ""), response.text
                )
            )

        return response.content
Exemplo n.º 10
0
    def test_get_url2_dict(self):
        request = DummyRequest()
        request.registry.settings = {
            "package": "my_project",
            "servers": {
                "srv": {
                    "url": "https://example.com/test_params",
                    "params": {
                        "MAP": "éàè"
                    }
                }
            },
        }
        request.scheme = "https"

        self.assertEqual(
            get_url2("test", "config://srv/icon.png?SALT=456", request,
                     set()).url(),
            "https://example.com/test_params/icon.png?MAP=%C3%A9%C3%A0%C3%A8&SALT=456",
        )
Exemplo n.º 11
0
    def __init__(self, server_iface: qgis.server.QgsServerInterface):
        super().__init__(server_iface)

        self.server_iface = server_iface
        self.initialized = False

        try:
            config.init(
                os.environ.get("GEOMAPFISH_CONFIG",
                               "/etc/qgisserver/geomapfish.yaml"))

            c2cwsgiutils.broadcast.init()

            DBSession = create_session_factory(  # noqa: ignore=N806
                config.get("sqlalchemy_slave.url"),
                config.get_config().get("sqlalchemy", {}))

            if "GEOMAPFISH_OGCSERVER" in os.environ:
                self.single = True
                self.ogcserver_accesscontrol = OGCServerAccessControl(
                    server_iface,
                    os.environ["GEOMAPFISH_OGCSERVER"],
                    os.environ["QGIS_PROJECT_FILE"],
                    config.get("srid"),
                    DBSession,
                )

                LOG.info("Use OGC server named '%s'.",
                         os.environ["GEOMAPFISH_OGCSERVER"])
                self.initialized = True
            elif "GEOMAPFISH_ACCESSCONTROL_CONFIG" in os.environ:
                self.single = False
                self.ogcserver_accesscontrols = {}
                with open(os.environ["GEOMAPFISH_ACCESSCONTROL_CONFIG"],
                          encoding="utf-8") as ac_config_file:
                    ac_config = yaml.safe_load(ac_config_file.read())

                for map_, map_config in ac_config.get("map_config").items():
                    map_config["access_control"] = OGCServerAccessControl(
                        server_iface, map_config["ogc_server"], map_,
                        config.get("srid"), DBSession)
                    self.ogcserver_accesscontrols[map_] = map_config
                LOG.info("Use config '%s'.",
                         os.environ["GEOMAPFISH_ACCESSCONTROL_CONFIG"])
                self.initialized = True
            elif "GEOMAPFISH_ACCESSCONTROL_BASE_URL" in os.environ:
                self.ogcserver_accesscontrols = {}
                single_ogc_server = None
                base_url = Url(os.environ["GEOMAPFISH_ACCESSCONTROL_BASE_URL"])
                session = DBSession()
                try:
                    from c2cgeoportal_commons.models.main import (  # pylint: disable=import-outside-toplevel
                        OGCServer, )

                    for ogcserver in session.query(OGCServer).all():
                        errors: Set[str] = set()
                        url = get_url2(
                            f"The OGC server '{ogcserver.name}'",
                            ogcserver.url,
                            None,
                            errors,
                            config.get_config().get("servers", {}),
                        )

                        if errors:
                            LOG.warning(
                                "Ignoring OGC server '%s', get error on parsing URL:\n%s",
                                ogcserver.name,
                                "\n".join(errors),
                            )
                            continue
                        if url is None:
                            LOG.warning(
                                "Ignoring OGC server '%s', the URL is None",
                                ogcserver.name)
                            continue
                        if (base_url.scheme == url.scheme
                                and base_url.netloc == url.netloc
                                and base_url.path == url.path):
                            query = url.query_lower
                            if "map" not in query:
                                if single_ogc_server is None:
                                    single_ogc_server = ogcserver
                                    LOG.debug(
                                        "OGC server '%s', 'map' is not in the parameters => single server?",
                                        ogcserver.name,
                                    )
                                else:
                                    LOG.error(
                                        "OGC server '%s', 'map' is not in the parameters and we already have a single OCG server '%s'",
                                        ogcserver.name,
                                        single_ogc_server.name,
                                    )
                                continue

                            map_ = url.query_lower["map"]
                            self.ogcserver_accesscontrols[map_] = {
                                "ogcserver":
                                ogcserver.name,
                                "access_control":
                                OGCServerAccessControl(
                                    server_iface,
                                    ogcserver.name,
                                    map_,
                                    config.get("srid"),
                                    DBSession,
                                    ogcserver=ogcserver,
                                ),
                            }
                            LOG.info("OGC server '%s' registered for map",
                                     ogcserver.name)
                        else:
                            LOG.debug(
                                "Ignoring OGC server '%s', Don't match the base URL '%s' and '%s'",
                                ogcserver.name,
                                base_url,
                                url,
                            )
                    if self.ogcserver_accesscontrols and single_ogc_server is not None:
                        if os.environ.get("QGIS_PROJECT_FILE"):
                            LOG.error(
                                "We have OGC servers with and without parameter MAP and a value in QGIS_PROJECT_FILE, fallback to single OGC server mode."
                            )
                            self.ogcserver_accesscontrols = {}
                        else:
                            LOG.error(
                                "We have OGC servers with and without parameter MAP but no value in QGIS_PROJECT_FILE, fallback to multiple OGC server mode."
                            )
                            single_ogc_server = None
                    if single_ogc_server is not None:
                        self.single = True
                        self.ogcserver_accesscontrol = OGCServerAccessControl(
                            server_iface,
                            single_ogc_server.name,
                            os.environ["QGIS_PROJECT_FILE"],
                            config.get("srid"),
                            DBSession,
                            single_ogc_server,
                        )

                        LOG.info("Use OGC server named '%s'.",
                                 single_ogc_server.name)
                    else:
                        self.single = False
                    self.initialized = True
                finally:
                    session.close()
            else:
                LOG.error(
                    "The environment variable 'GEOMAPFISH_OGCSERVER', 'GEOMAPFISH_ACCESSCONTROL_CONFIG' "
                    "or 'GEOMAPFISH_ACCESSCONTROL_BASE_URL' should be defined.",
                )

        except Exception:  # pylint: disable=broad-except
            LOG.error("Cannot setup GeoMapFishAccessControl", exc_info=True)

        server_iface.registerAccessControl(
            self, int(os.environ.get("GEOMAPFISH_POSITION", 100)))
Exemplo n.º 12
0
 def _vectortiles_layers(self, layer_theme: Dict[str, Any], layer: main.Layer, errors: Set[str]) -> None:
     style = get_url2(f"The VectorTiles layer '{layer.name}'", layer.style, self.request, errors=errors)
     layer_theme["style"] = style.url() if style is not None else None
     if layer.xyz:
         layer_theme["xyz"] = layer.xyz
Exemplo n.º 13
0
    async def _wms_getcap_cached(
        self, ogc_server: main.OGCServer
    ) -> Tuple[Optional[Url], Optional[bytes], Set[str]]:
        errors: Set[str] = set()
        url = get_url2(f"The OGC server '{ogc_server.name}'", ogc_server.url, self.request, errors)
        if errors or url is None:
            return url, None, errors

        # Add functionality params
        if (
            ogc_server.auth == main.OGCSERVER_AUTH_STANDARD
            and ogc_server.type == main.OGCSERVER_TYPE_MAPSERVER
        ):
            url.add_query(get_mapserver_substitution_params(self.request))

        url.add_query(
            {
                "SERVICE": "WMS",
                "VERSION": "1.1.1",
                "REQUEST": "GetCapabilities",
                "ROLE_IDS": "0",
                "USER_ID": "0",
            },
        )

        LOG.debug("Get WMS GetCapabilities for URL: %s", url)

        # Forward request to target (without Host Header)
        headers = dict(self.request.headers)

        # Add headers for Geoserver
        if ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER:
            headers["sec-username"] = "******"
            headers["sec-roles"] = "root"

        if url.hostname != "localhost" and "Host" in headers:
            headers.pop("Host")

        headers = restrict_headers(headers, self.headers_whitelist, self.headers_blacklist)

        try:
            content, content_type = await asyncio.get_event_loop().run_in_executor(
                None, get_http_cached, self.http_options, url, headers
            )
        except Exception:
            error = f"Unable to GetCapabilities from URL {url}"
            errors.add(error)
            LOG.error(error, exc_info=True)
            return url, None, errors

        # With wms 1.3 it returns text/xml also in case of error :-(
        if content_type.split(";")[0].strip() not in [
            "application/vnd.ogc.wms_xml",
            "text/xml",
        ]:
            error = (
                f"GetCapabilities from URL '{url}' returns a wrong Content-Type: {content_type}\n"
                f"{content.decode()}"
            )
            errors.add(error)
            LOG.error(error)
            return url, None, errors

        return url, content, errors
Exemplo n.º 14
0
    def _layer_attributes(self, url: str,
                          layer: str) -> Tuple[List[str], List[str]]:
        errors: Set[str] = set()

        request = _Request()
        request.registry.settings = self.config
        # Static schema will not be supported
        url_obj_ = get_url2("Layer", url, request, errors)
        if errors:
            print("\n".join(errors))
            return [], []
        if not url_obj_:
            print("No URL for: {}".format(url))
            return [], []
        url_obj: Url = url_obj_
        url_obj, headers, kwargs = self._build_url(url_obj)

        if url not in self.wmscap_cache:
            print("Get WMS GetCapabilities for URL: {}".format(url_obj))
            self.wmscap_cache[url] = None

            wms_getcap_url = (url_obj.clone().add_query({
                "SERVICE": "WMS",
                "VERSION": "1.1.1",
                "REQUEST": "GetCapabilities",
                "ROLE_IDS": "0",
                "USER_ID": "0",
            }).url())
            try:
                print("Get WMS GetCapabilities for URL {},\nwith headers: {}".
                      format(
                          wms_getcap_url,
                          " ".join([
                              "{}={}".format(
                                  h, v if h not in ("Authorization",
                                                    "Cookies") else "***")
                              for h, v in headers.items()
                          ]),
                      ))
                response = requests.get(wms_getcap_url,
                                        headers=headers,
                                        **kwargs)

                try:
                    self.wmscap_cache[url] = WebMapService(
                        None, xml=response.content)
                except Exception as e:
                    print(
                        colorize(
                            "ERROR! an error occurred while trying to "
                            "parse the GetCapabilities document.",
                            Color.RED,
                        ))
                    print(colorize(str(e), Color.RED))
                    print("URL: {}\nxml:\n{}".format(wms_getcap_url,
                                                     response.text))
                    if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE":
                        raise
            except Exception as e:
                print(colorize(str(e), Color.RED))
                print(
                    colorize(
                        "ERROR! Unable to GetCapabilities from URL: {},\nwith headers: {}"
                        .format(
                            wms_getcap_url,
                            " ".join([
                                "{}={}".format(
                                    h, v if h not in ("Authorization",
                                                      "Cookies") else "***")
                                for h, v in headers.items()
                            ]),
                        ),
                        Color.RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE":
                    raise

        wmscap = self.wmscap_cache[url]

        if url not in self.featuretype_cache:
            print("Get WFS DescribeFeatureType for URL: {}".format(url_obj))
            self.featuretype_cache[url] = None

            wfs_descrfeat_url = (url_obj.clone().add_query({
                "SERVICE": "WFS",
                "VERSION": "1.1.0",
                "REQUEST": "DescribeFeatureType",
                "ROLE_IDS": "0",
                "USER_ID": "0",
            }).url())
            try:
                response = requests.get(wfs_descrfeat_url,
                                        headers=headers,
                                        **kwargs)
            except Exception as e:
                print(colorize(str(e), Color.RED))
                print(
                    colorize(
                        "ERROR! Unable to DescribeFeatureType from URL: {}".
                        format(wfs_descrfeat_url),
                        Color.RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return [], []
                raise

            if not response.ok:
                print(
                    colorize(
                        "ERROR! DescribeFeatureType from URL {} return the error: {:d} {}"
                        .format(wfs_descrfeat_url, response.status_code,
                                response.reason),
                        Color.RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return [], []
                raise Exception("Aborted")

            try:
                describe = parseString(response.text)
                featurestype: Optional[Dict[str, Node]] = {}
                self.featuretype_cache[url] = featurestype
                for type_element in describe.getElementsByTagNameNS(
                        "http://www.w3.org/2001/XMLSchema", "complexType"):
                    cast(Dict[str, Node], featurestype)[
                        type_element.getAttribute("name")] = type_element
            except ExpatError as e:
                print(
                    colorize(
                        "ERROR! an error occurred while trying to "
                        "parse the DescribeFeatureType document.",
                        Color.RED,
                    ))
                print(colorize(str(e), Color.RED))
                print("URL: {}\nxml:\n{}".format(wfs_descrfeat_url,
                                                 response.text))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return [], []
                raise
            except AttributeError:
                print(
                    colorize(
                        "ERROR! an error occurred while trying to "
                        "read the Mapfile and recover the themes.",
                        Color.RED,
                    ))
                print("URL: {}\nxml:\n{}".format(wfs_descrfeat_url,
                                                 response.text))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return [], []
                raise
        else:
            featurestype = self.featuretype_cache[url]

        if featurestype is None:
            return [], []

        layers: List[str] = [layer]
        if wmscap is not None and layer in list(wmscap.contents):
            layer_obj = wmscap[layer]
            if layer_obj.layers:
                layers = [layer.name for layer in layer_obj.layers]

        attributes: List[str] = []
        for sub_layer in layers:
            # Should probably be adapted for other king of servers
            type_element = featurestype.get("{}Type".format(sub_layer))
            if type_element is not None:
                for element in type_element.getElementsByTagNameNS(
                        "http://www.w3.org/2001/XMLSchema", "element"):
                    if not element.getAttribute("type").startswith("gml:"):
                        attributes.append(element.getAttribute("name"))

        return attributes, layers
Exemplo n.º 15
0
def get_typed(
    name: str,
    value: str,
    types: Dict[str, Any],
    request: pyramid.request.Request,
    errors: Set[str],
    layer_name: str = None,
) -> Union[str, int, float, bool, None, List[Any], Dict[str, Any]]:
    prefix = "Layer '{}': ".format(
        layer_name) if layer_name is not None else ""
    type_ = {"type": "not init"}
    try:
        if name not in types:
            errors.add("{}Type '{}' not defined.".format(prefix, name))
            return None
        type_ = types[name]
        if type_.get("type", "string") == "string":
            return value
        if type_["type"] == "list":
            return [v.strip() for v in value.split(",")]
        if type_["type"] == "boolean":
            value = value.lower()
            if value in ["yes", "y", "on", "1", "true"]:
                return True
            if value in ["no", "n", "off", "0", "false"]:
                return False
            errors.add("{}The boolean attribute '{}'='{}' is not in "
                       "[yes, y, on, 1, true, no, n, off, 0, false].".format(
                           prefix, name, value.lower()))
        elif type_["type"] == "integer":
            return int(value)
        elif type_["type"] == "float":
            return float(value)
        elif type_["type"] == "date":
            date = dateutil.parser.parse(value,
                                         default=datetime.datetime(
                                             1, 1, 1, 0, 0, 0))  # type: ignore
            if date.time() != datetime.time(0, 0, 0):
                errors.add(
                    "{}The date attribute '{}'='{}' should not have any time".
                    format(prefix, name, value))
            else:
                return datetime.date.strftime(date.date(), "%Y-%m-%d")
        elif type_["type"] == "time":
            date = dateutil.parser.parse(value,
                                         default=datetime.datetime(
                                             1, 1, 1, 0, 0, 0))  # type: ignore
            if date.date() != datetime.date(1, 1, 1):
                errors.add(
                    "{}The time attribute '{}'='{}' should not have any date".
                    format(prefix, name, value))
            else:
                return datetime.time.strftime(date.time(), "%H:%M:%S")
        elif type_["type"] == "datetime":
            date = dateutil.parser.parse(value,
                                         default=datetime.datetime(
                                             1, 1, 1, 0, 0, 0))  # type: ignore
            return datetime.datetime.strftime(date, "%Y-%m-%dT%H:%M:%S")
        elif type_["type"] == "url":
            url = get_url2("{}The attribute '{}'".format(prefix, name), value,
                           request, errors)
            return url.url() if url else ""
        elif type_["type"] == "json":
            try:
                return cast(Dict[str, Any], json.loads(value))
            except Exception as e:
                errors.add("{}The attribute '{}'='{}' has an error: {}".format(
                    prefix, name, value, str(e)))
        else:
            errors.add("{}Unknown type '{}'.".format(prefix, type_["type"]))
    except Exception as e:
        errors.add(
            "{}Unable to parse the attribute '{}'='{}' with the type '{}', error:\n{}"
            .format(prefix, name, value, type_.get("type", "string"), str(e)))
    return None
Exemplo n.º 16
0
    async def _wms_getcap_cached(
        self, ogc_server: main.OGCServer
    ) -> Tuple[Optional[Url], Optional[bytes], Set[str]]:
        errors: Set[str] = set()
        url = get_url2("The OGC server '{}'".format(ogc_server.name),
                       ogc_server.url, self.request, errors)
        if errors or url is None:
            return url, None, errors

        # Add functionality params
        sparams = get_mapserver_substitution_params(self.request)
        url.add_query(sparams)

        url.add_query(
            {
                "SERVICE": "WMS",
                "VERSION": "1.1.1",
                "REQUEST": "GetCapabilities",
                "ROLE_ID": "0",
                "USER_ID": "0",
            }, )

        LOG.debug("Get WMS GetCapabilities for url: %s", url)

        # Forward request to target (without Host Header)
        headers = dict(self.request.headers)

        # Add headers for Geoserver
        if ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER:
            headers["sec-username"] = "******"
            headers["sec-roles"] = "root"

        if url.hostname != "localhost" and "Host" in headers:
            headers.pop("Host")

        try:
            response = await asyncio.get_event_loop().run_in_executor(
                None, get_http_cached, self.http_options, url, headers)
        except Exception:
            error = "Unable to GetCapabilities from URL {}".format(url)
            errors.add(error)
            LOG.error(error, exc_info=True)
            return url, None, errors

        if not response.ok:
            error = "GetCapabilities from URL {} return the error: {:d} {}".format(
                url, response.status_code, response.reason)
            errors.add(error)
            LOG.error(error)
            return url, None, errors

        # With wms 1.3 it returns text/xml also in case of error :-(
        if response.headers.get("Content-Type",
                                "").split(";")[0].strip() not in [
                                    "application/vnd.ogc.wms_xml",
                                    "text/xml",
                                ]:
            error = "GetCapabilities from URL {} returns a wrong Content-Type: {}\n{}".format(
                url, response.headers.get("Content-Type", ""), response.text)
            errors.add(error)
            LOG.error(error)
            return url, None, errors

        return url, response.content, errors
Exemplo n.º 17
0
    def test_get_url2(self):
        request = DummyRequest()
        request.registry.settings = {
            "package": "my_project",
            "servers": {
                "srv": "https://example.com/test",
                "srv_alt": "https://example.com/test/",
                "full_url": "https://example.com/test.xml",
                "srv_no_path": "https://example.com",
            },
        }
        request.scheme = "https"

        def static_url(path, **kwargs):
            del kwargs  # Unused
            return "http://server.org/" + path

        request.static_url = static_url

        self.assertEqual(
            get_url2("test", "static://pr:st/icon.png", request, set()).url(),
            "http://server.org/pr:st/icon.png",
        )
        self.assertEqual(
            get_url2("test", "static:///icon.png", request, set()).url(),
            "http://server.org//etc/geomapfish/static/icon.png",
        )
        self.assertEqual(
            get_url2("test", "config://srv/icon.png", request, set()).url(),
            "https://example.com/test/icon.png",
        )
        self.assertEqual(
            get_url2("test", "config://srv/", request, set()).url(),
            "https://example.com/test/")
        self.assertEqual(
            get_url2("test", "config://srv", request, set()).url(),
            "https://example.com/test")
        self.assertEqual(
            get_url2("test", "config://srv/icon.png?test=aaa", request,
                     set()).url(),
            "https://example.com/test/icon.png?test=aaa",
        )
        self.assertEqual(
            get_url2("test", "config://srv_alt/icon.png", request,
                     set()).url(),
            "https://example.com/test/icon.png",
        )
        self.assertEqual(
            get_url2("test", "config://full_url", request, set()).url(),
            "https://example.com/test.xml")
        self.assertEqual(
            get_url2("test", "http://example.com/icon.png", request,
                     set()).url(),
            "http://example.com/icon.png",
        )
        self.assertEqual(
            get_url2("test", "https://example.com/icon.png", request,
                     set()).url(),
            "https://example.com/icon.png",
        )
        errors: Set[str] = set()
        self.assertEqual(
            get_url2("test", "config://srv2/icon.png", request, errors=errors),
            None)
        self.assertEqual(
            errors,
            {
                "test: The server 'srv2' (config://srv2/icon.png) is not found in the config: [srv, srv_alt, full_url, srv_no_path]",
            },
        )
        self.assertEqual(
            get_url2("test",
                     "config://srv_no_path/icon.png",
                     request,
                     errors=errors).url(),
            "https://example.com/icon.png",
        )
        self.assertEqual(
            get_url2("test", "config://srv_no_path", request,
                     errors=errors).url(), "https://example.com")
Exemplo n.º 18
0
def get_typed(
    name: str,
    value: str,
    types: Dict[str, Any],
    request: pyramid.request.Request,
    errors: Set[str],
    layer_name: Optional[str] = None,
) -> Union[str, int, float, bool, None, List[Any], Dict[str, Any]]:
    """Get the typed (parsed) value of a metadata or a functionality."""
    prefix = f"Layer '{layer_name}': " if layer_name is not None else ""
    type_ = {"type": "not init"}
    try:
        if name not in types:
            errors.add(f"{prefix}Type '{name}' not defined.")
            return None
        type_ = types[name]
        if type_.get("type", "string") == "string":
            return value
        if type_["type"] == "list":
            return [v.strip() for v in value.split(",")]
        if type_["type"] == "boolean":
            value = value.lower()
            if value in ["yes", "y", "on", "1", "true"]:
                return True
            if value in ["no", "n", "off", "0", "false"]:
                return False
            errors.add(
                f"{prefix}The boolean attribute '{name}'='{value.lower()}' is not in "
                "[yes, y, on, 1, true, no, n, off, 0, false]."
            )
        elif type_["type"] == "integer":
            return int(value)
        elif type_["type"] == "float":
            return float(value)
        elif type_["type"] == "date":
            date = dateutil.parser.parse(value, default=datetime.datetime(1, 1, 1, 0, 0, 0))  # type: ignore
            if date.time() != datetime.time(0, 0, 0):
                errors.add(f"{prefix}The date attribute '{name}'='{value}' should not have any time")
            else:
                return datetime.date.strftime(date.date(), "%Y-%m-%d")
        elif type_["type"] == "time":
            date = dateutil.parser.parse(value, default=datetime.datetime(1, 1, 1, 0, 0, 0))  # type: ignore
            if date.date() != datetime.date(1, 1, 1):
                errors.add(f"{prefix}The time attribute '{name}'='{value}' should not have any date")
            else:
                return datetime.time.strftime(date.time(), "%H:%M:%S")
        elif type_["type"] == "datetime":
            date = dateutil.parser.parse(value, default=datetime.datetime(1, 1, 1, 0, 0, 0))  # type: ignore
            return datetime.datetime.strftime(date, "%Y-%m-%dT%H:%M:%S")
        elif type_["type"] == "url":
            url = get_url2(f"{prefix}The attribute '{name}'", value, request, errors)
            return url.url() if url else ""
        elif type_["type"] == "json":
            try:
                return cast(Dict[str, Any], json.loads(value))
            except Exception as e:
                errors.add(f"{prefix}The attribute '{name}'='{value}' has an error: {str(e)}")
        elif type_["type"] == "regex":
            pattern = type_["regex"]
            if re.match(pattern, value) is None:
                errors.add(
                    f"{prefix}The regex attribute '{name}'='{value}' "
                    f"does not match expected pattern '{pattern}'."
                )
            else:
                return value
        else:
            errors.add(f"{prefix}Unknown type '{type_['type']}'.")
    except Exception as e:
        errors.add(
            f"{prefix}Unable to parse the attribute '{name}'='{value}' with the type "
            f"'{type_.get('type', 'string')}', error:\n{e!s}"
        )
    return None
Exemplo n.º 19
0
 def url_description(self, request: pyramid.request.Request) -> str:
     errors: Set[str] = set()
     url = get_url2(self.name, self.url, request, errors)
     return url.url() if url else "\n".join(errors)