""" Module to implement Fiware services as a protocol. """ import json import os import tempfile import requests from MG.tools.postgis_api import PostGis from tools import const from .masterDriver import MasterDriver class FIWARE(MasterDriver): """ Class programming driver for FIWARE """ format = 'fiware' gdal_driver = 'FIWARE' driver_type = const.VECTOR_KEY name = const.FIWARE_KEY def to_local(self, layer, *args, **kwargs): """ Get remote source to out local environment Parameters ---------- layer: :obj:`Layer` args: optional Arguments kwargs: optional Arguments Returns ------- dict New parameters of the layer """ user = layer.user postgis_obj = PostGis('Public') entity = layer['entity_name'] foreign_table_name = 'FIWARE_' + entity version = layer.protocol.get_version(layer["ip"], layer["port"]) if version == 'KeyStone': uri_token = layer["url_token"] + 'auth/tokens' postgres_version = "V3" elif version == 'KeyRock': uri_token = layer["url_token"].replace('v1/', 'oauth2/token') postgres_version = "V1" else: raise TypeError("Version currently not supported") uri_cb = """http://{ip}:{port}/v2/entities""".format(ip=layer["ip"], port=layer["port"]) list_att = self.list(layer)[0] if list_att: if 'latitude' in list_att and 'longitude' in list_att: geo_type = 'LonLat' geo_att = 'longitude, latitude' elif 'location' in list_att: geo_type = 'location' geo_att = 'location' elif 'address' in list_att: geo_type = 'address' geo_att = 'address' else: raise TypeError("Georeferencing type not supported") else: raise TypeError("Entity not valid") status_wrapper_fiware = postgis_obj.\ wrapper_fiware_pg(user, foreign_table_name, postgres_version, uri_token, uri_cb, layer["application_id"], layer["application_secret"], layer["user"], layer["password"], layer["service"], layer["subservice"], entity, geo_type, geo_att, False) new_parameters = {'ip': postgis_obj.ip, 'port': postgis_obj.port, 'protocol': const.POSTGRESQL_KEY, 'driver_type': const.POSTGRESQL_KEY, 'user': postgis_obj.user, 'password': postgis_obj.passw, 'database_name': postgis_obj.dbname, 'layer_name': entity, 'table_view_name': status_wrapper_fiware['layer'], 'schema': user} return new_parameters def download(self, layer, dst, *args, **kwargs): """ Method to download the source from remote to local file. Parameters ---------- layer: :obj:`Layer` Layer from remote source dst: str Path to save the file args: list Arguments kwargs: dict Arguments Returns ------- success: str Path where the fil has been saved """ json_response = layer.protocol.get_entities(layer) entity_files = [] file = json.dumps(json_response) for i in json_response["features"]: if i["type"] not in entity_files: entity_files.append(i["type"]) for j in entity_files: layer.protocol.download(file, j) return dst def upload(self, layer, orig, *_, **__): """ Method to upload file from out local system to remote Parameters ---------- layer: :obj:`Layer` Layer from remote source orig: str Path in local system Returns ------- success: None """ # Upload file with the desired protocol layer.protocol.upload(layer, orig) def remove(self, source, *args): """ Remove sources Parameters ---------- source: str Path to remove args: list Arguments Returns ------- bool True if successful, False otherwise. """ postgis_obj = PostGis('public') layer = args[0] foreign_tables = postgis_obj.list_foreign_tables() if source in foreign_tables: # Removing, if exists, table in user's schema. # The method "to_local" has been executed earlier. postgis_obj = PostGis(layer.user) servers_to_remove = postgis_obj.get_foreign_server_from_ft( layer.user, source) for server in servers_to_remove: postgis_obj.delete_server_data_Wraper(server) return None try: server_name = list( PostGis('public').send_sql_command( """ SELECT foreign_server_name from information_schema.foreign_tables where foreign_table_name like '%{}%'; """.format(layer["table_view_name"]))) PostGis('public').delete_server_data_Wraper(server_name[0][0]) return True except Exception as err: return False def translate(self, src_layer, dst_driver): """ Translate layer from one driver to another Parameters ---------- src_layer: :obj:`Layer` Origin layer dst_driver: :obj:`Layer` Destiny layer Returns ------- success: list Resulting files """ tmp_dir = tempfile.mkdtemp(dir=const.TMP_DIRECTORY) result_files = [] file_name = src_layer["entity_name"] gdal_layer_source = src_layer.gdal_url('{}.geojson'.format(file_name)) file_result = os.path.join(tmp_dir, '{}.geojson'.format(file_name)) file_result = dst_driver.check_source(file_result) tempdir = tempfile.TemporaryDirectory() self.download(src_layer, tempdir.name) # Update layer new_cloud_parameters = {'driver_type': const.GJSON_KEY, 'source': "{}/{}.geojson".format(tempdir.name, file_name)} src_layer.cloud_parameters.update(new_cloud_parameters) command = 'ogr2ogr -overwrite -f "{output_format}" ' \ '"{output_connection}" "{input_connection}"'.\ format(output_format=dst_driver.gdal_driver, output_connection=file_result, input_connection=gdal_layer_source) result_files.append(file_result) os.system(command) def publish(self, layer, *_, **__): """ Publish on Geoserver Parameters ---------- layer: :obj:`Layer` Origin layer Returns ------- success: list Url with the layer servers created """ return None def check_source(self, *_): """ Check that source follow the naming rules of the driver Returns ------- success: str Formatted path to the source """ return None def get_source(self, layer, *_, **__): """ Get source path with the format of the driver Parameters ---------- layer: :obj: `Layer` Returns ------- success: str Formatted source """ return '{}'.format(layer['entity_name']) def set_source(self, layer, *sources): layer.parameters['entity_name'] = ":".join(sources) def check(self, layer): """ Check that source is available Parameters ---------- layer: :obj: `Layer` Returns ------- bool True if successful, False otherwise. """ exists_layer = layer.protocol.exists() if exists_layer: return True return False def create(self, *_, **__): """ With the execution of the wrapper, the foreign table is obtained from which the attributes that the user indicates will be extracted, for subsequent preview. Notes ----- This method will return None for all layers except Postgres, since once the wrapper is done, all layers are foreign tables. Returns ------- success: None """ return None def list(self, layer): """ Get the list of attributes and layer name of the source Parameters ---------- layer: :obj: `Layer` Returns ------- list List that contain the name layer and attributes """ list_entities = [] output_list = [] version = layer.protocol.get_version(layer["ip"], layer["port"]) access_token = layer.protocol.get_token(layer["user"], layer["password"]) if not layer["entity_name"] or layer["entity_name"] == ' ': raise TypeError("You need to set the entity name") else: uri_cb = """http://{ip}:{port}/v2/entities?type={entity}""".format( ip=layer["ip"], port=layer["port"], entity=layer["entity_name"]) if version == 'KeyStone': headers_get = {'Content-Type': 'application/json', 'Fiware-Service': layer["service"], 'Fiware-ServicePath': layer["subservice"], 'X-Auth-Token': access_token} response = requests.get(url=uri_cb, headers=headers_get, verify=False) elif version == 'KeyRock': headers_get = {'Fiware-Service': layer["service"], 'Fiware-ServicePath': layer["subservice"], 'X-Auth-Token': access_token} response = requests.get(url=uri_cb, headers=headers_get) else: raise TypeError("Version Currently not supported") if response.status_code in [200, 201]: json_response = json.loads(response.content.decode('utf-8')) if json_response[0]: list_attributes = list(json_response[0].keys()) list_entities.append(layer["entity_name"]) output_list.append(list_attributes) output_list.append(list_entities) else: raise TypeError("Entity not valid") else: raise TypeError("It has not been possible to access " "the requested information") return output_list def preview(self, *_): """ Get the info to preview Returns ------- bool True if successful. """ return True def prelist(self, layer): """ list the layers of sources to preview Parameters ---------- layer: :obj: `Layer` Returns ------- list List that contain the layer name """ output_list = [] type_id = [] head = ["type", "id"] version = layer.protocol.get_version(layer["ip"], layer["port"]) access_token = layer.protocol.get_token(layer["user"], layer["password"]) uri_cb = """http://{ip}:{port}/v2/entities""".format(ip=layer["ip"], port=layer["port"]) if version == 'KeyStone': headers_get = {'Content-Type': 'application/json', 'Fiware-Service': layer["service"], 'Fiware-ServicePath': layer["subservice"], 'X-Auth-Token': access_token} response = requests.get(url=uri_cb, headers=headers_get, verify=False) elif version == 'KeyRock': headers_get = {'Fiware-Service': layer["service"], 'Fiware-ServicePath': layer["subservice"], 'X-Auth-Token': access_token} response = requests.get(url=uri_cb, headers=headers_get) else: raise TypeError("Version Currently not supported") if response.status_code in [200, 201]: json_response = json.loads(response.content.decode('utf-8')) for i in json_response: layer = """{type}.{id}""".format(type=i["type"], id=i["id"]) type_id.append(layer) output_list.append(head) output_list.append(type_id) else: raise TypeError("It has not been possible to access " "the requested information") return output_list