diff --git a/FreeTAKServer/components/core/domain/controllers/dict_to_node_controller.py b/FreeTAKServer/components/core/domain/controllers/dict_to_node_controller.py index c0fde4ec..b588484e 100644 --- a/FreeTAKServer/components/core/domain/controllers/dict_to_node_controller.py +++ b/FreeTAKServer/components/core/domain/controllers/dict_to_node_controller.py @@ -4,7 +4,9 @@ from digitalpy.core.zmanager.response import Response from digitalpy.core.zmanager.action_mapper import ActionMapper from digitalpy.core.digipy_configuration.configuration import Configuration +from digitalpy.core.parsing.load_configuration import Configuration as LoadConf from digitalpy.core.domain.node import Node +from .domain import Domain from lxml import etree class DictToNodeController(Controller): @@ -16,6 +18,11 @@ def __init__( configuration: Configuration, ) -> None: super().__init__(request, response, sync_action_mapper, configuration) + self.domain_controller = Domain(request, response, sync_action_mapper, configuration) + + def initialize(self, request, response): + super().initialize(request, response) + self.domain_controller.initialize(request, response) def execute(self, method=None): return getattr(self, method)(**self.request.get_values()) @@ -48,14 +55,16 @@ def convert_dict_to_node( def serialize(self, dictionary, node): """recursively serialize a single layer of the given dictionary to a node object until a nested dictionary is found""" - for key, value in dictionary.items(): - self.add_value_to_node(key, value, node) - return node - + try: + for key, value in dictionary.items(): + self.add_value_to_node(key, value, node) + return node + except Exception as ex: + print(ex) def add_value_to_node(self, key, value, node): """add a value to a node object""" if key == "#text": - setattr(node, "INTAG", value) + setattr(node, "text", value) elif not hasattr(node, key.strip("@")): self.handle_missing_attribute(key, value, node) @@ -66,8 +75,11 @@ def add_value_to_node(self, key, value, node): self.serialize(value, getattr(node, key)) elif isinstance(value, list) and isinstance(getattr(node, key, None), list): - for l_item in value: - self.add_value_to_node(key, l_item, node) + self.serialize(value[0], getattr(node, key)[0]) + + for i in range(1,len(value)): + new_node = self.domain_controller.create_node(LoadConf(), key) + self.serialize(value[i], new_node) elif isinstance(getattr(node, key, None), list): self.serialize(value, getattr(node, key)[0]) diff --git a/FreeTAKServer/components/core/domain/controllers/domain.py b/FreeTAKServer/components/core/domain/controllers/domain.py index e8d31001..f79b1684 100644 --- a/FreeTAKServer/components/core/domain/controllers/domain.py +++ b/FreeTAKServer/components/core/domain/controllers/domain.py @@ -40,7 +40,7 @@ def add_child(self, node: Node, child: Node, **kwargs) -> None: """ return node.add_child(child) - def create_node(self, configuration: Configuration, object_class_name: str, id:str=str(uuid.uuid1()), **kwargs) -> None: + def create_node(self, configuration: Configuration, object_class_name: str, id:str=str(uuid.uuid1()), **kwargs) -> Node: """this method creates a new node object Args: @@ -59,6 +59,7 @@ def create_node(self, configuration: Configuration, object_class_name: str, id:s object_class_instance = object_class(configuration, self.domain, oid=oid) # set the module object self.response.set_value("model_object", object_class_instance) + return object_class_instance def _extend_domain(self, domain: ModuleType, extended_domain: dict) -> ModuleType: """this method is responsible for adding domain extensions from a given component diff --git a/FreeTAKServer/components/core/domain/domain/_dest.py b/FreeTAKServer/components/core/domain/domain/_dest.py index af26cb0d..e7302e95 100644 --- a/FreeTAKServer/components/core/domain/domain/_dest.py +++ b/FreeTAKServer/components/core/domain/domain/_dest.py @@ -6,8 +6,8 @@ class dest(CoTNode): - def __init__(self, configuration: Configuration, model): - super().__init__(self.__class__.__name__, configuration, model) + def __init__(self, configuration: Configuration, model, oid=None): + super().__init__(self.__class__.__name__, configuration, model, oid) self.cot_attributes["callsign"] = None @CoTProperty diff --git a/FreeTAKServer/components/core/domain/domain/_emergency.py b/FreeTAKServer/components/core/domain/domain/_emergency.py index b1610e67..1b786bd8 100644 --- a/FreeTAKServer/components/core/domain/domain/_emergency.py +++ b/FreeTAKServer/components/core/domain/domain/_emergency.py @@ -23,7 +23,7 @@ def __init__(self, configuration, model): self.cot_attributes["alert"] = None # if true the Emergency beacon is canceled self.cot_attributes["cancel"] = None - self.cot_attributes["INTAG"] = None + self.cot_attributes["text"] = None @CoTProperty def type(self): @@ -50,9 +50,9 @@ def cancel(self, cancel=None): self.cot_attributes["cancel"] = cancel @CoTProperty - def INTAG(self): - return self.cot_attributes.get("INTAG", None) + def text(self): + return self.cot_attributes.get("text", None) - @INTAG.setter - def INTAG(self, INTAG=None): - self.cot_attributes["INTAG"] = INTAG + @text.setter + def text(self, text=None): + self.cot_attributes["text"] = text diff --git a/FreeTAKServer/components/extended/emergency/controllers/emergency_general_controller.py b/FreeTAKServer/components/extended/emergency/controllers/emergency_general_controller.py index 7e448108..0d94503d 100644 --- a/FreeTAKServer/components/extended/emergency/controllers/emergency_general_controller.py +++ b/FreeTAKServer/components/extended/emergency/controllers/emergency_general_controller.py @@ -61,10 +61,13 @@ def convert_type(self, model_object, **kwargs)->None: def filter_by_distance(self, emergency: Event): """filter who receives this emergency based on their distance from the emergency""" - self.connections = self.retrieve_users() - for connection_obj in self.connections: - if self.validate_user_distance(emergency, connection_obj): - self.request.get_value('recipients').append(str(connection_obj.get_oid())) + if config.EmergencyRadius==0: + self.request.set_value('recipients', "*") + else: + self.connections = self.retrieve_users() + for connection_obj in self.connections: + if self.validate_user_distance(emergency, connection_obj): + self.request.get_value('recipients').append(str(connection_obj.get_oid())) def validate_user_distance(self, emergency: Event, connection): connection_model_object = connection.model_object @@ -73,7 +76,6 @@ def validate_user_distance(self, emergency: Event, connection): # check that the distance between the user and the emergency is less than 10km # TODO: this hardcoded distance should be added to the business rules return ( - config.EmergencyRadius==0 or distance.geodesic( (connection_location.lat, connection_location.lon), (emergency.point.lat, emergency.point.lon), diff --git a/FreeTAKServer/components/extended/emergency/domain/_emergency.py b/FreeTAKServer/components/extended/emergency/domain/_emergency.py index b1610e67..1b786bd8 100644 --- a/FreeTAKServer/components/extended/emergency/domain/_emergency.py +++ b/FreeTAKServer/components/extended/emergency/domain/_emergency.py @@ -23,7 +23,7 @@ def __init__(self, configuration, model): self.cot_attributes["alert"] = None # if true the Emergency beacon is canceled self.cot_attributes["cancel"] = None - self.cot_attributes["INTAG"] = None + self.cot_attributes["text"] = None @CoTProperty def type(self): @@ -50,9 +50,9 @@ def cancel(self, cancel=None): self.cot_attributes["cancel"] = cancel @CoTProperty - def INTAG(self): - return self.cot_attributes.get("INTAG", None) + def text(self): + return self.cot_attributes.get("text", None) - @INTAG.setter - def INTAG(self, INTAG=None): - self.cot_attributes["INTAG"] = INTAG + @text.setter + def text(self, text=None): + self.cot_attributes["text"] = text diff --git a/FreeTAKServer/core/configuration/MainConfig.py b/FreeTAKServer/core/configuration/MainConfig.py index 3debaa36..69f3a47b 100644 --- a/FreeTAKServer/core/configuration/MainConfig.py +++ b/FreeTAKServer/core/configuration/MainConfig.py @@ -9,7 +9,7 @@ # the version information of the server (recommended to leave as default) -FTS_VERSION = "FreeTAKServer-2.0.66" +FTS_VERSION = "FreeTAKServer-2.0.69" API_VERSION = "3.0" ROOTPATH = "/" MAINPATH = Path(__file__).parent.parent.parent diff --git a/FreeTAKServer/core/parsers/JsonController.py b/FreeTAKServer/core/parsers/JsonController.py index f6468858..351ed598 100644 --- a/FreeTAKServer/core/parsers/JsonController.py +++ b/FreeTAKServer/core/parsers/JsonController.py @@ -34,7 +34,7 @@ def serialize_emergency_post(self, json: dict): full_json = { "event": { "@uid": str(uuid.uuid4()), - "@type": "b-a-o-tbl", + "@type": "EmergencyAlert", "@how": "h-e", "@time": None, # these will be automatically created during object serialization "@start": None, @@ -66,7 +66,7 @@ def serialize_emergency_delete(self, json): "@time": None, # these will be automatically created during object serialization "@start": None, "@stale": None, - "@type": "b-a-o-can", + "@type": "EmergencyCancelled", "@uid": json.get("uid"), "@version": "2.0", "detail": { diff --git a/FreeTAKServer/services/rest_api_service/rest_api_service_main.py b/FreeTAKServer/services/rest_api_service/rest_api_service_main.py index 4694cabc..d45b19ae 100644 --- a/FreeTAKServer/services/rest_api_service/rest_api_service_main.py +++ b/FreeTAKServer/services/rest_api_service/rest_api_service_main.py @@ -55,6 +55,7 @@ from FreeTAKServer.core.parsers.JsonController import JsonController from FreeTAKServer.core.serializers.SqlAlchemyObjectController import SqlAlchemyObjectController from FreeTAKServer.components.extended.excheck.controllers.ExCheckController import ExCheckController +from .views.connections_view_controller import ManageConnections app = Flask(__name__) login_manager = LoginManager() @@ -154,24 +155,7 @@ def authenticate(token): @socketio.on('users') @socket_auth(session=session) def show_users(empty=None): - output = dbController.query_user() - for i in range(0, len(output)): - try: - original = output[i] - output[i] = output[i].__dict__ - print(output[i]) - try: - output[i]['callsign'] = original.CoT.detail.contact.callsign - output[i]['team'] = original.CoT.detail._group.name - except: - output[i]['callsign'] = "undefined" - output[i]['team'] = "undefined" - del (output[i]['_sa_instance_state']) - del (output[i]['CoT_id']) - del (output[i]['CoT']) - except Exception as e: - logger.error(str(e)) - socketio.emit('userUpdate', json.dumps({"Users": output})) + socketio.emit('userUpdate', json.dumps({"Users": ManageConnections().get_users()})) @socketio.on('logs') @@ -1987,6 +1971,7 @@ def delete_repeated_messages(self): # this will require changing it from using the API Pipe to use the ZManager instead ManageEmergency.decorators.append(auth.login_required) +app.add_url_rule('/ManageEmergency/', view_func=ManageEmergency.as_view('/ManageEmergency/'), methods=["POST", "GET","DELETE"]) app.add_url_rule('/ManageGeoObject/', view_func=ManageGeoObjects.as_view('/ManageGeoObject/'), methods=["POST", "GET","DELETE"]) APPLICATION_PROTOCOL = "xml" diff --git a/FreeTAKServer/services/rest_api_service/views/connections_view_controller.py b/FreeTAKServer/services/rest_api_service/views/connections_view_controller.py new file mode 100644 index 00000000..27eec26f --- /dev/null +++ b/FreeTAKServer/services/rest_api_service/views/connections_view_controller.py @@ -0,0 +1,27 @@ +from FreeTAKServer.services.rest_api_service.views.base_view_controller import BaseViewController +from FreeTAKServer.core.configuration.CreateLoggerController import CreateLoggerController +from FreeTAKServer.core.configuration.LoggingConstants import LoggingConstants + +loggingConstants = LoggingConstants(log_name="FTS-ManageConnectionsView") +logger = CreateLoggerController("FTS-ManageConnectionsView", logging_constants=loggingConstants).getLogger() + +class ManageConnections(BaseViewController): + decorators = [] + + def __init__(self) -> None: + pass + + def get_users(self): + response = self.make_request("GetAllConnections", service_id="rest_api_service") + connections = response.get_value("connections") + output = [] + for connection in connections: + try: + serialized_user = { + "callsign": connection.model_object.detail.contact.callsign, + "team": connection.model_object.detail._group.name, + } + output.append(serialized_user) + except AttributeError as ex: + logger.error("emergency model object missing attribute %s", ex) + return output \ No newline at end of file diff --git a/FreeTAKServer/services/rest_api_service/views/emergency_view.py b/FreeTAKServer/services/rest_api_service/views/emergency_view.py index 0fe5312a..3ef35c54 100644 --- a/FreeTAKServer/services/rest_api_service/views/emergency_view.py +++ b/FreeTAKServer/services/rest_api_service/views/emergency_view.py @@ -33,11 +33,14 @@ def get_emergency(self): output = {"json_list": []} for emergency in emergencies: try: + name = emergency.detail.contact.callsign + if emergency.detail.contact.callsign is None: + name = emergency.detail.emergency.text serialized_emergency = { "lat": emergency.point.lat, "lon": emergency.point.lon, "type": emergency.detail.emergency.type, - "name": emergency.detail.contact.callsign, + "name": name, "uid": emergency.uid } output["json_list"].append(serialized_emergency) @@ -48,18 +51,16 @@ def get_emergency(self): def post_emergency(self): jsondata = request.get_json(force=True) jsonobj = JsonController().serialize_emergency_post(jsondata) - emergency_object = SendEmergencyController(jsonobj).getCoTObject() - self.make_request("SaveEmergency", {"model_object": emergency_object.modelObject}) - APIPipe.put(emergency_object) - return emergency_object.modelObject.getuid(), 200 - + self.make_request("EmergencyAlert", {"dictionary": jsonobj}, False, "tcp_cot_service") # send the request output to the tcp cot service + self.make_request("EmergencyAlert", {"dictionary": jsonobj}, False, "ssl_cot_service") # send the request output to the ssl cot service + return jsonobj.get("event").get("@uid"), 200 + def delete_emergency(self) -> str: """delete an emergency from the emergency persistence """ jsondata = request.get_json(force=True) jsonobj = JsonController().serialize_emergency_delete(jsondata) - emergency_object = SendEmergencyController(jsonobj).getCoTObject() - APIPipe.put(emergency_object) - self.make_request("DeleteEmergency", {"model_object": emergency_object.modelObject}) - return 'success', 200 + self.make_request("EmergencyCancelled", {"dictionary": jsonobj}, False, "tcp_cot_service") # send the request output to the tcp cot service + self.make_request("EmergencyCancelled", {"dictionary": jsonobj}, False, "ssl_cot_service") # send the request output to the ssl cot service + return jsonobj.get("@uid"), 200 diff --git a/FreeTAKServer/services/ssl_cot_service/ssl_cot_service_main.py b/FreeTAKServer/services/ssl_cot_service/ssl_cot_service_main.py index 6129f57b..2c308622 100644 --- a/FreeTAKServer/services/ssl_cot_service/ssl_cot_service_main.py +++ b/FreeTAKServer/services/ssl_cot_service/ssl_cot_service_main.py @@ -291,6 +291,7 @@ def component_handler(self, xml_cot): request.set_format("pickled") human_readable_type = self.get_human_readable_type(dict_cot) request.set_action(human_readable_type) + dict_cot["event"]["@type"] = human_readable_type request.set_context("XMLCoT") request.set_sender(self.__class__.__name__.lower()) request.set_value("dictionary", dict_cot) diff --git a/FreeTAKServer/services/tcp_cot_service/tcp_cot_service_main.py b/FreeTAKServer/services/tcp_cot_service/tcp_cot_service_main.py index 39d4d322..c493c945 100644 --- a/FreeTAKServer/services/tcp_cot_service/tcp_cot_service_main.py +++ b/FreeTAKServer/services/tcp_cot_service/tcp_cot_service_main.py @@ -296,6 +296,7 @@ def component_handler(self, xml_cot): request.set_format("pickled") human_readable_type = self.get_human_readable_type(dict_cot) request.set_action(human_readable_type) + dict_cot["event"]["@type"] = human_readable_type request.set_context("XMLCoT") request.set_sender(self.__class__.__name__.lower()) request.set_value("dictionary", dict_cot) diff --git a/setup.py b/setup.py index 85ef5013..520e1ae8 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ packages=find_packages( include=["FreeTAKServer", "FreeTAKServer.*", "*.json", "*.ini", "*.conf"] ), - version="2.0.66", + version="2.0.69", license="EPL-2.0", description="An open source server for the TAK family of applications.", long_description=long_description,