예제 #1
0
    def get_project(self,
                    url: urllib.parse.ParseResult,
                    project: QgsProject = None,
                    timestamp: datetime = None) -> Tuple[QgsProject, datetime]:
        """ Create or return a proect
        """
        # Securit check
        path = Path(url.path)
        if not path.is_absolute():
            raise ValueError("file path must be absolute not %s" % path)

        exists = False
        if path.suffix not in ALLOWED_SFX:
            for sfx in ALLOWED_SFX:
                path = path.with_suffix(sfx)
                exists = path.is_file()
                if exists:
                    break
        else:
            exists = path.is_file()

        if not exists:
            LOGGER.error("File protocol handler: File not found: %s",
                         str(path))
            raise FileNotFoundError(str(path))

        modified_time = datetime.fromtimestamp(path.stat().st_mtime)
        if timestamp is None or timestamp < modified_time:
            cachmngr = componentmanager.get_service(
                '@3liz.org/cache-manager;1')
            project = cachmngr.read_project(str(path))
            timestamp = modified_time

        return project, timestamp
예제 #2
0
    def update_entry(self, key: str) -> bool:
        """ Update the cache

            :param key: The key of the entry to update
            :param force: Force updating entry

            :return: true if the entry has been updated
        """
        url = self.resolve_alias(key)
    
        scheme = url.scheme or self._default_scheme
        # Retrieve the protocol-handler
        try:
            store = componentmanager.get_service('@3liz.org/cache/protocol-handler;1?scheme=%s' % scheme)
        except componentmanager.FactoryNotFoundError:
            LOGGER.error("No protocol handler found for %s", scheme) 
            raise FileNotFoundError(key)

        # Get details for the project
        details = self._cache.peek(key)
        if details is not None:
            project, timestamp  = store.get_project( url, **details._asdict())
            updated = timestamp != details.timestamp
        else:
            project, timestamp = store.get_project(url)
            updated = True
        self._cache[key] = CacheDetails(project, timestamp)
        return updated
def register_policy(collection, wpspolicy=False) -> None:
    """ Register filters
    """
    from pyqgisservercontrib.core import componentmanager

    if not wpspolicy:
        LOGGER.info("Lizmap policy is used only with wps policy")
        return

    configservice = componentmanager.get_service('@3liz.org/config-service;1')
    configservice.add_section('lizmap')

    with_policy = configservice.get('lizmap', 'policy', fallback=None)
    if with_policy:

        policyfile = Path(with_policy)
        if not policyfile.exists():
            LOGGER.error(
                "Lizmap Policy file is defined but does not exists: %s",
                policyfile)
            return

        mngr = PolicyManager.initialize(policyfile)

        @blockingfilter()
        def _filter(handler: RequestHandler) -> None:
            mngr.add_policy(handler)

        collection.append(_filter)
예제 #4
0
    def get_project(
            self,
            url: Optional[urllib.parse.ParseResult],
            strict: Optional[bool] = None,
            project: Optional[QgsProject] = None,
            timestamp: Optional[datetime] = None
    ) -> Tuple[QgsProject, datetime]:
        """ Create or return a project

            .. versionadded:: 1.3.2

            Supports the postgres:///projectname syntax
        """
        if url:
            urlstr, modified_time = _check_unsafe_url(self._insecure, url)
        elif project:
            urlstr = project.fileName()
            modified_time = project.lastModified().toPyDateTime()
        else:
            raise ValueError('Cannot get uri from arguments')

        if timestamp is None or timestamp < modified_time:
            cachemngr = componentmanager.get_service(
                '@3liz.org/cache-manager;1')
            project = cachemngr.read_project(urlstr, strict=strict)
            timestamp = modified_time

        return project, timestamp
예제 #5
0
def register_policy(collection, wpspolicy=False) -> None:
    """ Register filters
    """
    from pyqgisservercontrib.core import componentmanager
    configservice = componentmanager.get_service('@3liz.org/config-service;1')

    configservice.add_section('contrib:profiles')

    with_profiles = configservice.get('server','profiles', fallback=None) or \
                    configservice.get('contrib:profiles' , 'config', fallback=None)
    if with_profiles:
        http_proxy = configservice.getboolean('server', 'http_proxy', False)
        mngr = ProfileMngr.initialize(with_profiles, wpspolicy=wpspolicy)

        with_referer = configservice.getboolean('contrib:profiles',
                                                'with_referer',
                                                fallback=False)

        @blockingfilter()
        def default_filter(handler: RequestHandler) -> None:
            if not mngr.apply_profile(
                    'default', handler, http_proxy, with_referer=with_referer):
                raise HTTPError(403, reason="Unauthorized profile")

        @blockingfilter(pri=-1000, uri=r"p/(?P<profile>(?:(?!/wfs3/?).)*)")
        def profile_filter(handler: RequestHandler) -> str:
            # Remove profile from argument list
            profile = handler.path_kwargs.pop('profile')
            if not mngr.apply_profile(
                    profile, handler, http_proxy, with_referer=with_referer):
                raise HTTPError(403, reason="Unauthorized profile")
            return f"p/{profile}"

        collection.extend([profile_filter, default_filter])
예제 #6
0
    def get_project(
            self,
            url: Optional[urllib.parse.ParseResult],
            strict: Optional[bool] = None,
            project: Optional[QgsProject] = None,
            timestamp: Optional[datetime] = None
    ) -> Tuple[QgsProject, datetime]:
        """ Create or return a proect
        """
        if url:
            path = self._check_file(Path(url.path))
        elif project:
            path = self._check_file(project.fileName())
        else:
            raise ValueError('Cannot get path from arguments')

        if not path:
            LOGGER.error("File protocol handler: File not found: %s",
                         str(path))
            raise FileNotFoundError(str(path))

        modified_time = datetime.fromtimestamp(path.stat().st_mtime)
        if timestamp is None or timestamp < modified_time:
            cachmngr = componentmanager.get_service(
                '@3liz.org/cache-manager;1')
            project = cachmngr.read_project(str(path), strict=strict)
            timestamp = modified_time

        return project, timestamp
예제 #7
0
    def get_project(self,
                    url: urllib.parse.ParseResult,
                    project: QgsProject = None,
                    timestamp: datetime = None) -> Tuple[QgsProject, datetime]:
        """ Create or return a proect
        """
        params = {k: v[0] for k, v in parse_qs(url.query).items()}

        try:
            project = params.pop('project')
            schema = params.pop('schema', 'public')
            database = params.pop('dbname', None)
        except KeyError as exc:
            LOGGER.error("Postgres handler: Missing parameter %s: %s",
                         url.geturl(), str(exc))
            raise FileNotFoundError(url.geturl())

        connexion_params = dict(
            host=url.hostname,
            port=url.port,
            user=url.username,
            password=url.password,
            database=database,
            # Treats remaining params as supported psql client options
            **params)

        # Connect to database and check modification time
        try:
            LOGGER.debug("**** Postgresql connection params %s",
                         connexion_params)
            conn = psycopg2.connect(**connexion_params)
            cursor = conn.cursor()
            cursor.execute(
                "select metadata from %s.qgis_projects where name='%s'" %
                (schema, project))
            if cursor.rowcount <= 0:
                raise FileNotFoundError(url.geturl())
            metadata = cursor.fetchone()[0]
            LOGGER.debug("**** Postgres metadata for '%s': %s", project,
                         metadata)
            conn.close()
        except psycopg2.OperationalError as e:
            LOGGER.error("Postgres handler Connection error: %s", str(e))
            raise FileNotFoundError(url.geturl())
        except psycopg2.Error as e:
            LOGGER.error("Postgres handler Connection error: %s", str(e))
            raise RuntimeError("Connection failed: %s", url.geturl())

        modified_time = datetime.fromisoformat(metadata['last_modified_time'])
        if timestamp is None or timestamp < modified_time:
            cachmngr = componentmanager.get_service(
                '@3liz.org/cache-manager;1')
            project = cachmngr.read_project(url.geturl())
            timestamp = modified_time

        return project, timestamp
예제 #8
0
    def get_project_factory( self, key: str ):
        """ Return project store create function for the given key
        """
        url = self.resolve_alias(key)

        scheme = url.scheme or self._default_scheme
        # Retrieve the protocol-handler
        try:
            store = componentmanager.get_service('@3liz.org/cache/protocol-handler;1?scheme=%s' % scheme)
        except componentmanager.FactoryNotFoundError:
            LOGGER.error("No protocol handler found for %s", scheme)
            raise FileNotFoundError(key)
       
        return partial(store.get_project,url)
예제 #9
0
    def get_protocol_handler(self, key: str, scheme: Optional[str]) -> Any:
        """ Find protocol handler for the given scheme
        """
        scheme = scheme or self._default_scheme
        # Check for allowed schemes
        if self._allowed_schemes != '*' and scheme not in self._allowed_schemes:
            LOGGER.error("Scheme %s not allowed", scheme)
            raise PathNotAllowedError(key)
        # Retrieve the protocol-handler
        try:
            store = componentmanager.get_service(
                '@3liz.org/cache/protocol-handler;1?scheme=%s' % scheme)
        except componentmanager.FactoryNotFoundError:
            # Fallback to Qgis storage handler
            store = QgisStorageHandler()

        return store
예제 #10
0
    def get_project(
            self,
            url: urllib.parse.ParseResult,
            strict: Optional[bool] = None,
            project: Optional[QgsProject] = None,
            timestamp: Optional[datetime] = None
    ) -> Tuple[QgsProject, datetime]:
        """ Create or return a project
        """
        uri = urlunparse(url)

        metadata = self.get_storage_metadata(uri)
        modified_time = metadata.lastModified.toPyDateTime()

        if timestamp is None or timestamp < modified_time:
            cachmngr = componentmanager.get_service(
                '@3liz.org/cache-manager;1')
            project = cachmngr.read_project(uri, strict=strict)
            timestamp = modified_time

        return project, timestamp
예제 #11
0
def get_cacheservice() -> QgsCacheManager:
    return componentmanager.get_service(CACHE_MANAGER_CONTRACTID)
예제 #12
0
 def __init__(self):
     cnf = componentmanager.get_service('@3liz.org/config-service;1')
     self._insecure = cnf.getboolean('projects.cache',
                                     'insecure',
                                     fallback=False)
예제 #13
0
class BadLayerHandler(QgsProjectBadLayerHandler):

    def __init__(self):
        super().__init__()
        self.badLayerNames = set()

    def handleBadLayers( self, layers ) -> None:
        """ See https://qgis.org/pyqgis/3.0/core/Project/QgsProjectBadLayerHandler.html
        """
        super().handleBadLayers( layers )

        nameElements = (l.firstChildElement("layername") for l in layers if l)
        self.badLayerNames = set(elem.text() for elem in nameElements if elem)

    def validatLayers( self, project: QgsProject ) -> bool:
        """ Check layers
            
            If layers are excluded do not count them as bad layers
            see https://github.com/qgis/QGIS/pull/33668
        """
        if self.badLayerNames:
            LOGGER.debug("Found bad layers: %s", self.badLayerNames)
            restricteds = set(QgsServerProjectUtils.wmsRestrictedLayers(project))
            return self.badLayerNames.issubset(restricteds)
        return True


cacheservice = componentmanager.get_service(CACHE_MANAGER_CONTRACTID)

예제 #14
0
    def get_project(self,
                    url: urllib.parse.ParseResult,
                    project: QgsProject = None,
                    timestamp: datetime = None) -> Tuple[QgsProject, datetime]:
        """ Create or return a project

            .. versionadded:: 1.3.2

            Supports the postgres://projectname syntax
        """
        if self._insecure:
            LOGGER.warning(
                "Setting postgres connexion parameters in insecure mode %s",
                url.geturl())
            params = {k: v[0] for k, v in parse_qs(url.query).items()}
            try:
                project = params.pop('project')
                schema = params.pop('schema', 'public')
                database = params.pop('dbname', None)
            except KeyError as exc:
                LOGGER.error("Postgres handler: Missing parameter %s: %s",
                             url.geturl(), str(exc))
                raise FileNotFoundError(url.geturl())

            connexion_params = dict(
                host=url.hostname,
                port=url.port,
                user=url.username,
                password=url.password,
                database=database,
                # Treats remaining params as supported psql client options
                **params)
            urlstr = url.geturl()
        else:
            # Secure mode: allow only secure parameter
            params = {
                k: v[0]
                for k, v in parse_qs(url.query).items()
                if k in ALLOWED_SECURE_PARAMS
            }
            try:
                project = params.pop('project')
                schema = params.pop('schema', 'public')
                database = params.pop('dbname', None)
            except KeyError as exc:
                LOGGER.error("Postgres handler: Missing parameter %s: %s",
                             url.geturl(), str(exc))
                raise FileNotFoundError(url.geturl())

            connexion_params = dict(
                user=url.username,
                database=database,
                # Treats remaining params as supported psql client options
                **params)
            netloc = '%s@' % url.username if url.username else ''
            # Create secure url
            urlstr = "postgres://%s/?%s" % (netloc, '&'.join(
                '%s=%s' % (k, v) for k, v in params.items()))

        # Connect to database and check modification time
        try:
            LOGGER.debug("**** Postgresql connection params %s",
                         connexion_params)
            conn = psycopg2.connect(**connexion_params)
            cursor = conn.cursor()
            cursor.execute(
                "select metadata from %s.qgis_projects where name='%s'" %
                (schema, project))
            if cursor.rowcount <= 0:
                raise FileNotFoundError(url.geturl())
            metadata = cursor.fetchone()[0]
            LOGGER.debug("**** Postgres metadata for '%s': %s", project,
                         metadata)
            conn.close()
        except psycopg2.OperationalError as e:
            LOGGER.error("Postgres handler Connection error: %s", str(e))
            raise FileNotFoundError(urlstr)
        except psycopg2.Error as e:
            LOGGER.error("Postgres handler Connection error: %s", str(e))
            raise RuntimeError("Connection failed: %s", urlstr)

        modified_time = datetime.fromisoformat(metadata['last_modified_time'])
        if timestamp is None or timestamp < modified_time:
            cachmngr = componentmanager.get_service(
                '@3liz.org/cache-manager;1')
            project = cachmngr.read_project(urlstr)
            timestamp = modified_time

        return project, timestamp