def __init__(self, tenant, logger): """Constructor :param Logger logger: Application logger """ self.tenant = tenant self.logger = logger config_handler = RuntimeConfig("legend", logger) config = config_handler.tenant_config(tenant) # get internal QGIS server URL from config self.qgis_server_url = config.get( 'default_qgis_server_url', 'http://localhost:8001/ows/').rstrip('/') + '/' # get path to legend images from config self.legend_images_path = config.get('legend_images_path', 'legends/') # temporary target dir for any Base64 encoded legend images # NOTE: this dir will be cleaned up automatically on reload self.images_temp_dir = None self.resources = self.load_resources(config) self.permissions_handler = PermissionsReader(tenant, logger)
def __init__(self, tenant, mail, app): """Constructor :param str tenant: Tenant ID :param flask_mail.Mail mail: Application mailer :param App app: Flask application """ self.tenant = tenant self.mail = mail self.app = app self.logger = app.logger config_handler = RuntimeConfig("dbAuth", self.logger) config = config_handler.tenant_config(tenant) db_url = config.get('db_url') # get password constraints from config self.password_constraints = { 'min_length': config.get('password_min_length', 8), 'max_length': config.get('password_max_length', -1), 'constraints': config.get('password_constraints', []), 'min_constraints': config.get('password_min_constraints', 0), 'constraints_message': config.get( 'password_constraints_message', "Password does not match constraints" ) } db_engine = DatabaseEngine() self.config_models = ConfigModels(db_engine, db_url) self.User = self.config_models.model('users')
def __init__(self, tenant, logger): """Constructor :param str tenant: Tenant ID :param Logger logger: Application logger """ self.tenant = tenant self.logger = logger config_handler = RuntimeConfig("featureInfo", logger) config = config_handler.tenant_config(tenant) if config.get('default_info_template'): self.default_info_template = config.get('default_info_template') elif config.get('default_info_template_base64'): self.default_info_template = self.b64decode( config.get('default_info_template_base64'), default_info_template, "default info template" ) else: self.default_info_template = default_info_template self.default_wms_url = config.get( 'default_qgis_server_url', 'http://localhost:8001/ows/') self.data_service_url = config.get( 'data_service_url', '/api/v1/data/').rstrip('/') + '/' self.resources = self.load_resources(config) self.permissions_handler = PermissionsReader(tenant, logger) self.db_engine = DatabaseEngine()
def __init__(self, tenant, db_engine, logger): self.tenant = tenant self._db_engine = db_engine self.logger = logger config_handler = RuntimeConfig("adminGui", logger) self._config = config_handler.tenant_config(tenant)
def __init__(self, tenant, logger): """Constructor :param str tenant: Tenant ID :param Logger logger: Application logger """ self.tenant = tenant self.logger = logger config_handler = RuntimeConfig("mapViewer", logger) config = config_handler.tenant_config(tenant) # path to QWC2 files self.qwc2_path = config.get('qwc2_path', 'qwc2/') # QWC service URLs for config.json self.auth_service_url = self.__sanitize_url( config.get('auth_service_url')) self.ccc_config_service_url = self.__sanitize_url( config.get('ccc_config_service_url')) self.data_service_url = self.__sanitize_url( config.get('data_service_url')) self.dataproduct_service_url = self.__sanitize_url( config.get('dataproduct_service_url')) self.document_service_url = self.__sanitize_url( config.get('document_service_url', config.get('feature_report_service_url'))) self.elevation_service_url = self.__sanitize_url( config.get('elevation_service_url')) self.landreg_service_url = self.__sanitize_url( config.get('landreg_service_url')) self.mapinfo_service_url = self.__sanitize_url( config.get('mapinfo_service_url')) self.permalink_service_url = self.__sanitize_url( config.get('permalink_service_url')) self.plotinfo_service_url = self.__sanitize_url( config.get('plotinfo_service_url')) self.proxy_service_url = self.__sanitize_url( config.get('proxy_service_url')) self.search_service_url = self.__sanitize_url( config.get('search_service_url')) self.search_data_service_url = self.__sanitize_url( config.get('search_data_service_url')) # QWC service URLs for themes.json self.ogc_service_url = self.__sanitize_url( config.get('ogc_service_url', 'http://localhost:5013/')) self.info_service_url = self.__sanitize_url( config.get('info_service_url', self.ogc_service_url)) self.legend_service_url = self.__sanitize_url( config.get('legend_service_url', self.ogc_service_url)) self.print_service_url = self.__sanitize_url( config.get('print_service_url', self.ogc_service_url)) # get config dir for tenant self.config_dir = os.path.dirname( RuntimeConfig.config_file_path('mapViewer', tenant)) self.resources = self.load_resources(config) self.permissions_handler = PermissionsReader(tenant, logger)
def __init__(self, tenant, logger): """Constructor :param Logger logger: Application logger """ self.logger = logger config_handler = RuntimeConfig("search", logger) config = config_handler.tenant_config(tenant) self.resources = self.load_resources(config) self.db_engine = DatabaseEngine() self.db = self.db_engine.db_engine(config.get('db_url'))
def load_resources(self): """Load service resources from config.""" # read config config_handler = RuntimeConfig("data", self.logger) config = config_handler.tenant_config(self.tenant) # get service resources datasets = {} for resource in config.resources().get('datasets', []): datasets[resource['name']] = resource return { 'datasets': datasets }
def put(self, dataset, id): """Update a dataset feature Update dataset feature with ID from a GeoJSON Feature and return it as a GeoJSON Feature. """ config_handler = RuntimeConfig("data", app.logger) config = config_handler.tenant_config(tenant_handler.tenant()) edit_user_field = config.get("edit_user_field", None) edit_timestamp_field = config.get("edit_timestamp_field", None) if request.is_json: # parse request data (NOTE: catches invalid JSON) feature = api.payload if isinstance(feature, dict): data_service = data_service_handler() internal_fields = {} if edit_user_field: feature["properties"][edit_user_field] = get_auth_user() internal_fields[edit_user_field] = { 'name': edit_user_field, 'data_type': 'text' } if edit_timestamp_field: feature["properties"][edit_timestamp_field] = str( datetime.now()) internal_fields[edit_timestamp_field] = { 'name': edit_timestamp_field, 'data_type': 'text' } result = data_service.update(get_auth_user(), dataset, id, feature, internal_fields) if 'error' not in result: result['feature']['properties'] = dict( filter(lambda x: x[0] not in internal_fields, result['feature']['properties'].items())) return result['feature'] else: error_code = result.get('error_code') or 404 error_details = result.get('error_details') or {} api.abort(error_code, result['error'], **error_details) else: api.abort(400, "JSON is not an object") else: api.abort(400, "Request data is not JSON")
def __init__(self, tenant, db_engine, logger): self.tenant = tenant self._db_engine = db_engine self.logger = logger config_handler = RuntimeConfig("adminGui", logger) try: self._config = config_handler.tenant_config(tenant) except FileNotFoundError: self._config = { "db_url": os.environ.get("DB_URL", "postgresql:///?service=qwc_configdb"), "config_generator_service_url": os.environ.get("CONFIG_GENERATOR_SERVICE_URL", "http://qwc-config-service:9090") }
def get(self): """Submit query Returns additional information at clicked map position. """ args = mapinfo_parser.parse_args() tenant = tenant_handler.tenant() config_handler = RuntimeConfig("mapinfo", app.logger) config = config_handler.tenant_config(tenant) db = db_engine.db_engine(config.get('db_url')) table = config.get('info_table') info_geom_col = config.get('info_geom_col') info_display_col = config.get('info_display_col') info_title = config.get('info_title') try: pos = args['pos'].split(',') pos = [float(pos[0]), float(pos[1])] except: return jsonify({"error": "Invalid position specified"}) try: srid = int(re.match(r'epsg:(\d+)', args['crs'], re.IGNORECASE).group(1)) except: return jsonify({"error": "Invalid projection specified"}) conn = db.connect() sql = sql_text(""" SELECT {display} FROM {table} WHERE ST_contains({table}.{geom}, ST_SetSRID(ST_Point(:x, :y), :srid)) LIMIT 1; """.format(display=info_display_col, geom=info_geom_col, table=table)) result = conn.execute(sql, x=pos[0], y=pos[1], srid=srid) info_result = [] for row in result: info_result = [[info_title, row[info_display_col]]] conn.close() return jsonify({"results": info_result})
def __init__(self, tenant, logger): """Constructor :param Logger logger: Application logger """ self.tenant = tenant self.logger = logger config_handler = RuntimeConfig("data", self.logger) config = config_handler.tenant_config(self.tenant) self.attachments_base_dir = config.get('attachments_base_dir', '/tmp/qwc_attachments/') self.max_file_size = int( config.get('max_attachment_file_size', 10 * 1024 * 1024)) self.allowed_extensions = config.get('allowed_attachment_extensions', '').split(",")
def __init__(self, tenant, logger): """Constructor :param Logger logger: Application logger """ self.logger = logger self.tenant = tenant config_handler = RuntimeConfig("search", logger) config = config_handler.tenant_config(tenant) self.solr_service_url = config.get( 'solr_service_url', 'http://localhost:8983/solr/gdi/select') self.word_split_re = re.compile( config.get('word_split_re', r'[\s,.:;"]+')) self.default_search_limit = config.get('search_result_limit', 50) self.resources = self.load_resources(config) self.permissions_handler = PermissionsReader(tenant, logger)
def get(self): """Get available land register templates""" tenant = tenant_handler.tenant() config_handler = RuntimeConfig("landreg", app.logger) config = config_handler.tenant_config(tenant) qgis_server_url = config.get('qgis_server_url') default_landreg_layout = config.get('default_landreg_layout') project = config.get('landreg_project') params = { "SERVICE": "WMS", "VERSION": "1.3.0", "REQUEST": "GetProjectSettings", } url = qgis_server_url.rstrip("/") + "/" + project req = requests.get(url, params=params) layouts = [] try: capabilities = parseString(req.text) templates = capabilities.getElementsByTagName("WMS_Capabilities")[0]\ .getElementsByTagName("Capability")[0]\ .getElementsByTagName("ComposerTemplates")[0] for template in templates.getElementsByTagName("ComposerTemplate"): name = template.getAttribute("name") composerMap = template.getElementsByTagName("ComposerMap")[0] entry = { "name": name, "map": { "width": float(composerMap.getAttribute("width")), "height": float(composerMap.getAttribute("height")), "name": composerMap.getAttribute("name") }, "default": name == default_landreg_layout } layouts.append(entry) except: pass return jsonify(layouts)
def __init__(self, tenant, mail, app): """Constructor :param str tenant: Tenant ID :param flask_mail.Mail mail: Application mailer :param App app: Flask application """ self.tenant = tenant self.mail = mail self.app = app self.logger = app.logger config_handler = RuntimeConfig("dbAuth", self.logger) config = config_handler.tenant_config(tenant) db_url = config.get('db_url') db_engine = DatabaseEngine() self.config_models = ConfigModels(db_engine, db_url) self.User = self.config_models.model('users')
def __init__(self, tenant, logger): """Constructor :param str tenant: Tenant ID :param Logger logger: Application logger """ self.tenant = tenant self.logger = logger config_handler = RuntimeConfig("ogc", logger) config = config_handler.tenant_config(tenant) # get internal QGIS server URL from config # (default: local qgis-server container) self.default_qgis_server_url = config.get( 'default_qgis_server_url', 'http://localhost:8001/ows/').rstrip('/') + '/' self.resources = self.load_resources(config) self.permissions_handler = PermissionsReader(tenant, logger)
def load_dataset(tenant): config_handler = RuntimeConfig("elevation", app.logger) config = config_handler.tenant_config(tenant) dsfn = config.get('elevation_dataset') if dsfn is None: abort(Response('elevation_dataset undefined', 500)) raster = gdal.Open(dsfn) if not raster: abort(Response('Failed to open dataset', 500)) gtrans = raster.GetGeoTransform() if not gtrans: abort(Response('Failed to read dataset geotransform', 500)) rasterSpatialRef = osr.SpatialReference() if rasterSpatialRef.ImportFromWkt(raster.GetProjectionRef()) != 0: abort(Response('Failed to parse dataset projection', 500)) band = raster.GetRasterBand(1) if not band: abort(Response('Failed to open dataset raster band', 500)) rasterUnitsToMeters = 1 if band.GetUnitType() == "ft": rasterUnitsToMeters = 0.3048 noDataValue = band.GetNoDataValue() if not noDataValue: noDataValue = None dataset = { "raster": raster, "band": band, "spatialRef": rasterSpatialRef, "geoTransform": gtrans, "unitsToMeters": rasterUnitsToMeters, "noDataValue": noDataValue } return dataset
def __get_link(self, identity, program, path, args): tenant = tenant_handler.tenant() permissions_handler = PermissionsReader(tenant, app.logger) permitted_resources = permissions_handler.resource_permissions( 'external_links', identity, program) if not permitted_resources: app.logger.warning( "Identity %s is not allowed to open link for program %s" % (identity, program)) api.abort(404, 'Unable to open link') config_handler = RuntimeConfig("ext", app.logger) config = config_handler.tenant_config(tenant_handler.tenant()) program_map = config.resources().get("external_links", []) link = None for entry in program_map: if entry["name"] == program: link = entry["url"] break if not link: app.logger.warning("No link configured for program %s" % (program)) api.abort(404, 'Unable to open link') parts = parse.urlsplit(link) query = dict(parse.parse_qsl(parts.query)) for key in query: query[key] = query[key].replace('$tenant$', tenant) query.update(args) parts = parts._replace(query=parse.urlencode(query)) if path: parts = parts._replace(path=os.path.dirname(parts.path) + "/" + path) link = parts.geturl() api.logger.info("Proxying " + link) return link
def post(self, dataset, id): """Update relation values for the specified dataset Return success status for each relation value. """ args = post_relations_parser.parse_args() try: payload = json.loads(args['values']) except: payload = None if not isinstance(payload, dict): api.abort(400, "JSON is not an object") data_service = data_service_handler() config_handler = RuntimeConfig("data", app.logger) config = config_handler.tenant_config(tenant_handler.tenant()) upload_user_field_suffix = config.get("upload_user_field_suffix", None) edit_user_field = config.get("edit_user_field", None) edit_timestamp_field = config.get("edit_timestamp_field", None) # Check if dataset with specified id exists if not data_service.is_editable(get_auth_user(), dataset, id): api.abort(404, "Dataset or feature not found or permission error") # Validate attachments attachments = attachments_service_handler() for key in request.files: filedata = request.files[key] attachment_valid, message = attachments.validate_attachment( dataset, filedata) if not attachment_valid: api.abort( 404, "Attachment validation failed for " + key + ": " + message) # Save attachments saved_attachments = {} internal_fields = [] for key in request.files: filedata = request.files[key] slug = attachments.save_attachment(dataset, filedata) if not slug: for slug in saved_attachments.values(): attachments.remove_attachment(dataset, slug) api.abort(404, "Failed to save attachment: " + key) else: saved_attachments[key] = slug parts = key.lstrip("file:").split("__") table = parts[0] field = parts[1] index = parts[2] payload[table]["records"][int(index)][ table + "__" + field] = "attachment://" + slug if upload_user_field_suffix: upload_user_field = table + "__" + field + "__" + upload_user_field_suffix payload[table]["records"][int( index)][upload_user_field] = get_auth_user() internal_fields.append(upload_user_field) ret = {} haserrors = False for (rel_table, rel_data) in payload.items(): fk_field = rel_data.get("fk", None) ret[rel_table] = {"fk": fk_field, "records": []} tbl_prefix = rel_table + "__" for rel_record in rel_data.get("records", []): # Set foreign key for new records if rel_record.get("__status__", "") == "new": rel_record[tbl_prefix + fk_field] = id if rel_record.get(tbl_prefix + fk_field, None) != id: rel_record["__error__"] = "FK validation failed" ret[rel_table]["records"].append(rel_record) haserrors = True else: entry = { "type": "Feature", "id": rel_record["id"] if "id" in rel_record else None, "properties": { k[len(tbl_prefix):]: v for k, v in rel_record.items() if k.startswith(tbl_prefix) } } table_internal_fields = { n[len(tbl_prefix):]: { 'name': n[len(tbl_prefix):], 'data_type': 'text' } for n in internal_fields if n.startswith(tbl_prefix) } if edit_user_field: entry["properties"][edit_user_field] = get_auth_user() table_internal_fields[edit_user_field] = { 'name': edit_user_field, 'data_type': 'text' } if edit_timestamp_field: entry["properties"][edit_timestamp_field] = str( datetime.now()) table_internal_fields[edit_timestamp_field] = { 'name': edit_timestamp_field, 'data_type': 'text' } if not "__status__" in rel_record: ret[rel_table]["records"].append(rel_record) continue elif rel_record["__status__"] == "new": result = data_service.create(get_auth_user(), rel_table, entry, table_internal_fields) elif rel_record["__status__"] == "changed": (newattachments, oldattachments) = self.attachments_diff( data_service, attachments, dataset, rel_table, rel_record["id"], entry, table_internal_fields, upload_user_field_suffix) result = data_service.update(get_auth_user(), rel_table, rel_record["id"], entry, table_internal_fields) self.cleanup_attachments( attachments, dataset, newattachments if "error" in result else oldattachments) elif rel_record["__status__"].startswith("deleted"): (newattachments, oldattachments) = self.attachments_diff( data_service, attachments, dataset, rel_table, rel_record["id"], entry, table_internal_fields, upload_user_field_suffix, True) if upload_user_field_suffix: data_service.update(get_auth_user(), rel_table, rel_record["id"], entry, table_internal_fields) result = data_service.destroy(get_auth_user(), rel_table, rel_record["id"]) self.cleanup_attachments( attachments, dataset, newattachments if "error" in result else oldattachments) else: continue if "error" in result: rel_record["error"] = result["error"] rel_record["error_details"] = result.get( 'error_details') or {} ret[rel_table]["records"].append(rel_record) haserrors = True elif "feature" in result: rel_record = {(rel_table + "__" + k): v for k, v in result['feature'] ['properties'].items() if not k in table_internal_fields} rel_record["id"] = result['feature']["id"] ret[rel_table]["records"].append(rel_record) return {"relationvalues": ret, "success": not haserrors}
def put(self, dataset, id): """Update a dataset feature Update dataset feature with ID from a GeoJSON Feature and return it as a GeoJSON Feature. """ args = feature_multipart_parser.parse_args() try: feature = json.loads(args['feature']) except: feature = None if not isinstance(feature, dict): api.abort(400, "feature is not an object") config_handler = RuntimeConfig("data", app.logger) config = config_handler.tenant_config(tenant_handler.tenant()) upload_user_field_suffix = config.get("upload_user_field_suffix", None) edit_user_field = config.get("edit_user_field", None) edit_timestamp_field = config.get("edit_timestamp_field", None) # Validate attachments attachments = attachments_service_handler() for key in request.files: filedata = request.files[key] attachment_valid, message = attachments.validate_attachment( dataset, filedata) if not attachment_valid: api.abort( 404, "Attachment validation failed for " + key + ": " + message) # Save attachments saved_attachments = {} internal_fields = {} for key in request.files: filedata = request.files[key] slug = attachments.save_attachment(dataset, filedata) if not slug: for slug in saved_attachments.values(): attachments.remove_attachment(dataset, slug) api.abort(404, "Failed to save attachment: " + key) else: saved_attachments[key] = slug field = key.lstrip("file:") feature["properties"][field] = "attachment://" + slug if upload_user_field_suffix: upload_user_field = field + "__" + upload_user_field_suffix feature["properties"][upload_user_field] = get_auth_user() internal_fields[upload_user_field] = { 'name': upload_user_field, 'data_type': 'text' } data_service = data_service_handler() prev = data_service.show(get_auth_user(), dataset, id, None) if prev: prev_feature = prev["feature"] # If a non-empty attachment field value is changed, delete the attachment keys = list(feature["properties"].keys()) for key in keys: if key in prev_feature["properties"] and prev_feature[ "properties"][key] and str( prev_feature["properties"][key]).startswith( "attachment://") and feature["properties"][ key] != prev_feature["properties"][key]: attachments.remove_attachment( dataset, prev_feature["properties"][key].lstrip( "attachment://")) if upload_user_field_suffix: upload_user_field = key + "__" + upload_user_field_suffix feature["properties"][ upload_user_field] = get_auth_user() internal_fields[upload_user_field] = { 'name': upload_user_field, 'data_type': 'text' } if edit_user_field: feature["properties"][edit_user_field] = get_auth_user() internal_fields[edit_user_field] = { 'name': edit_user_field, 'data_type': 'text' } if edit_timestamp_field: feature["properties"][edit_timestamp_field] = str(datetime.now()) internal_fields[edit_timestamp_field] = { 'name': edit_timestamp_field, 'data_type': 'text' } result = data_service.update(get_auth_user(), dataset, id, feature, internal_fields) if 'error' not in result: result['feature']['properties'] = dict( filter(lambda x: x[0] not in internal_fields, result['feature']['properties'].items())) return result['feature'] else: for slug in saved_attachments.values(): attachments.remove_attachment(dataset, slug) error_code = result.get('error_code') or 404 error_details = result.get('error_details') or {} api.abort(error_code, result['error'], **error_details)
def post(self): """Submit query Return map print """ post_params = dict( urlparse.parse_qsl(request.get_data().decode('utf-8'))) app.logger.info("POST params: %s" % post_params) tenant = tenant_handler.tenant() config_handler = RuntimeConfig("landreg", app.logger) config = config_handler.tenant_config(tenant) db = db_engine.db_engine(config.get('db_url')) qgis_server_url = config.get('qgis_server_url') project = config.get('landreg_project') landreg_printinfo_table = config.get('landreg_printinfo_table') landreg_print_layers = config.get('landreg_print_layers') params = { "SERVICE": "WMS", "VERSION": "1.3.0", "REQUEST": "GetPrint", "FORMAT": "PDF" } params.update(post_params) # Normalize parameter keys to upper case params = {k.upper(): v for k, v in params.items()} # Set LAYERS and OPACITIES params["LAYERS"] = landreg_print_layers params["OPACITIES"] = ",".join( map(lambda item: "255", params["LAYERS"].split(","))) # Determine center of extent extent = list(map(lambda x: float(x), params["EXTENT"].split(","))) x = 0.5 * (extent[0] + extent[2]) y = 0.5 * (extent[1] + extent[3]) # Determine lieferdatum and nfgeometer conn = db.connect() sql = sql_text(""" SELECT nfgeometer, lieferdatum, anschrift, kontakt, gemeinde FROM {table} WHERE ST_CONTAINS(geometrie, ST_SetSRID(ST_MakePoint(:x, :y), 2056)); """.format(table=landreg_printinfo_table)) sql_result = conn.execute(sql, x=x, y=y).fetchone() if sql_result: params["NFGEOMETER"] = sql_result["nfgeometer"] params["LIEFERDATUM"] = sql_result["lieferdatum"] params["ANSCHRIFT"] = sql_result["anschrift"] params["KONTAKT"] = sql_result["kontakt"] params["GEMEINDE"] = sql_result["gemeinde"] conn.close() # Prefix params with composer map name: Extent, scale, rotation params["map0:EXTENT"] = params["EXTENT"] del params["EXTENT"] params["map0:SCALE"] = params["SCALE"] del params["SCALE"] params["map0:ROTATION"] = params["ROTATION"] del params["ROTATION"] if "GRID_INTERVAL_X" in params: params["map0:GRID_INTERVAL_X"] = params["GRID_INTERVAL_X"] del params["GRID_INTERVAL_X"] if "GRID_INTERVAL_Y" in params: params["map0:GRID_INTERVAL_Y"] = params["GRID_INTERVAL_Y"] del params["GRID_INTERVAL_Y"] # Forward to QGIS server url = qgis_server_url.rstrip("/") + "/" + project req = requests.post(url, timeout=120, data=params) app.logger.info("Forwarding request to %s\n%s" % (req.url, params)) response = Response(stream_with_context( req.iter_content(chunk_size=1024)), status=req.status_code) response.headers['content-type'] = req.headers['content-type'] if req.headers['content-type'] == 'application/pdf': response.headers['content-disposition'] = \ 'attachment; filename=' + project + '.' + params['FORMAT'].lower() return response
def __init__(self, tenant, logger): """Constructor :param str tenant: Tenant ID :param Logger logger: Application logger """ self.tenant = tenant self.logger = logger config_handler = RuntimeConfig("mapViewer", logger) config = config_handler.tenant_config(tenant) # path to QWC2 files self.qwc2_path = config.get('qwc2_path', 'qwc2/') # QWC service URLs for config.json self.auth_service_url = self.__sanitize_url( config.get('auth_service_url')) self.ccc_config_service_url = self.__sanitize_url( config.get('ccc_config_service_url')) self.data_service_url = self.__sanitize_url( config.get('data_service_url')) self.dataproduct_service_url = self.__sanitize_url( config.get('dataproduct_service_url')) self.document_service_url = self.__sanitize_url( config.get('document_service_url', config.get('feature_report_service_url'))) self.elevation_service_url = self.__sanitize_url( config.get('elevation_service_url')) self.landreg_service_url = self.__sanitize_url( config.get('landreg_service_url')) self.mapinfo_service_url = self.__sanitize_url( config.get('mapinfo_service_url')) self.permalink_service_url = self.__sanitize_url( config.get('permalink_service_url')) self.plotinfo_service_url = self.__sanitize_url( config.get('plotinfo_service_url')) self.proxy_service_url = self.__sanitize_url( config.get('proxy_service_url')) self.search_service_url = self.__sanitize_url( config.get('search_service_url')) self.search_data_service_url = self.__sanitize_url( config.get('search_data_service_url')) # QWC service URLs for themes.json self.ogc_service_url = self.__sanitize_url( config.get('ogc_service_url', 'http://localhost:5013/')) self.info_service_url = self.__sanitize_url( config.get('info_service_url', self.ogc_service_url)) self.legend_service_url = self.__sanitize_url( config.get('legend_service_url', self.ogc_service_url)) self.print_service_url = self.__sanitize_url( config.get('print_service_url', self.ogc_service_url)) self.show_restricted_themes = config.get('show_restricted_themes', False) self.show_restricted_themes_whitelist = config.get('show_restricted_themes_whitelist', "") # get config dir for tenant self.config_dir = os.path.dirname( RuntimeConfig.config_file_path('mapViewer', tenant) ) # temporary target dir for any Base64 encoded thumbnail images # NOTE: this dir will be cleaned up automatically on reload self.images_temp_dir = None self.resources = self.load_resources(config) self.permissions_handler = PermissionsReader(tenant, logger)