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
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)
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
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])
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
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
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)
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
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
def get_cacheservice() -> QgsCacheManager: return componentmanager.get_service(CACHE_MANAGER_CONTRACTID)
def __init__(self): cnf = componentmanager.get_service('@3liz.org/config-service;1') self._insecure = cnf.getboolean('projects.cache', 'insecure', fallback=False)
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)
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