diff --git a/src/osintbuddy/elements/base.py b/src/osintbuddy/elements/base.py index 0053d09..13fc5bd 100644 --- a/src/osintbuddy/elements/base.py +++ b/src/osintbuddy/elements/base.py @@ -19,18 +19,18 @@ class BaseElement(object): """ def __init__(self, **kwargs): self.label: str = '' - self.placeholder: str = '' - - for key, value in kwargs.items(): - if key == 'label' or key == 'placeholder': - setattr(self, key, value) - - def _base_blueprint(self): - return { - 'type': self.node_type, - 'label': self.label, - } - + if entity_type := kwargs.get('label'): + setattr(self, 'label', entity_type) + + def _base_entity_element(self, **kwargs): + base_element = {} + if kwargs: + base_element = { + k: v for k, v in kwargs.items() + } + base_element['label'] = self.label + base_element['type'] = self.element_type + return base_element class BaseInput(BaseElement): pass diff --git a/src/osintbuddy/elements/displays.py b/src/osintbuddy/elements/displays.py index d80a181..31c34f8 100644 --- a/src/osintbuddy/elements/displays.py +++ b/src/osintbuddy/elements/displays.py @@ -2,135 +2,123 @@ class Title(BaseDisplay): - node_type: str = 'title' + element_type: str = 'title' - def __init__(self, title='', subtitle='', text='', **kwargs): + def __init__(self, value='', **kwargs): super().__init__(**kwargs) - self.title: str = title - self.subtitle: str = subtitle - self.text: str = text + self.element = { + "value": value, + } - def json(self): - blueprint = self._base_blueprint() - blueprint['title'] = self.title - blueprint['subtitle'] = self.subtitle - blueprint['text'] = self.text - return blueprint + def to_dict(self): + return self._base_entity_element(**self.element) class Text(BaseDisplay): - node_type: str = 'section' + element_type: str = 'section' def __init__(self, value='', icon="123", **kwargs): super().__init__(**kwargs) - self.value = value - self.icon = icon + self.element = { + "value": value, + "icon": icon + } - def json(self): - blueprint = self._base_blueprint() - blueprint['value'] = self.value - blueprint['icon'] = self.icon - return blueprint + def to_dict(self): + return self._base_entity_element(**self.element) class Empty(BaseDisplay): - node_type: str = 'empty' + element_type: str = 'empty' def __init__(self, **kwargs): super().__init__(**kwargs) - def json(self): - blueprint = self._base_blueprint() - return blueprint + def to_dict(self): + return self._base_entity_element() class CopyText(BaseDisplay): - node_type: str = 'copy-text' + element_type: str = 'copy-text' def __init__(self, value='', **kwargs): super().__init__(**kwargs) - self.value = value + self.element = { + "value": value + } - def json(self): - blueprint = self._base_blueprint() - blueprint['value'] = self.value - return blueprint + def to_dict(self): + return self._base_entity_element(**self.element) class CopyCode(BaseDisplay): - node_type: str = 'copy-code' + element_type: str = 'copy-code' def __init__(self, value='', **kwargs): super().__init__(**kwargs) - self.value = value + self.element = { + "value": value + } - def json(self): - blueprint = self._base_blueprint() - blueprint['value'] = self.value - return blueprint + def to_dict(self): + return self._base_entity_element(**self.element) class Json(BaseDisplay): - node_type: str = 'json' + element_type: str = 'json' def __init__(self, **kwargs): super().__init__(**kwargs) - def json(self): - blueprint = self._base_blueprint() - return blueprint + def to_dict(self): + return self._base_entity_element() class Image(BaseDisplay): - node_type: str = 'image' + element_type: str = 'image' def __init__(self, **kwargs): super().__init__(**kwargs) - def json(self): - blueprint = self._base_blueprint() - return blueprint + def to_dict(self): + return self._base_entity_element() class Pdf(BaseDisplay): - node_type: str = 'pdf' + element_type: str = 'pdf' def __init__(self, **kwargs): super().__init__(**kwargs) - def json(self): - blueprint = self._base_blueprint() - return blueprint + def to_dict(self): + return self._base_entity_element() class Video(BaseDisplay): - node_type: str = 'video' + element_type: str = 'video' def __init__(self, **kwargs): super().__init__(**kwargs) - def json(self): - blueprint = self._base_blueprint() - return blueprint + def to_dict(self): + return self._base_entity_element() class List(BaseDisplay): - node_type: str = 'list' + element_type: str = 'list' def __init__(self, **kwargs): super().__init__(**kwargs) - def json(self): - blueprint = self._base_blueprint() - return blueprint + def to_dict(self): + return self._base_entity_element() class Table(BaseDisplay): - node_type: str = 'table' + element_type: str = 'table' def __init__(self, **kwargs): super().__init__(**kwargs) - def json(self): - blueprint = self._base_blueprint() - return blueprint + def to_dict(self): + return self._base_entity_element() diff --git a/src/osintbuddy/elements/inputs.py b/src/osintbuddy/elements/inputs.py index 246c7ee..2647763 100644 --- a/src/osintbuddy/elements/inputs.py +++ b/src/osintbuddy/elements/inputs.py @@ -4,7 +4,7 @@ class UploadFileInput(BaseInput): """ - The UploadFileInput class represents an upload file input node used + !!WORK_IN_PROGRESS!! The UploadFileInput class represents an upload file input node used in the OsintBuddy plugin system. value : Any The initial value for the input node. @@ -17,20 +17,18 @@ class UploadFileInput(BaseInput): class Plugin(OBPlugin): node = [UploadFileInput(supported_files=['.pdf', '.docx'])] """ - node_type: str = "upload" + element_type: str = "upload" def __init__(self, value="", supported_files=[], icon="IconFileUpload", **kwargs): super().__init__(**kwargs) - self.value: Any = value - self.icon: str = icon - self.supported_files: List[str] = supported_files + self.element = { + "value": value, + "icon": icon, + "supported_files": supported_files, + } - def json(self): - node = self._base_blueprint() - node["value"] = self.value - node["icon"] = self.icon - node["supported_files"] = self.supported_files - return node + def to_dict(self): + return self._base_entity_element(**self.element) class TextInput(BaseInput): @@ -47,18 +45,16 @@ class TextInput(BaseInput): class Plugin(OBPlugin): node = [TextInput(label='Email search', placeholder='Enter email')] """ - node_type: str = "text" + element_type: str = "text" def __init__(self, value="", default="", icon="IconAlphabetLatin", **kwargs): super().__init__(**kwargs) - self.value: str = value - self.icon: str = icon - - def json(self): - node = self._base_blueprint() - node["value"] = self.value - node["icon"] = self.icon - return node + self.element = { + "value": value, + "icon": icon + } + def to_dict(self): + return self._base_entity_element(**self.element) class DropdownInput(BaseInput): @@ -79,23 +75,23 @@ class Plugin(OBPlugin): ) ] """ - node_type: str = "dropdown" + element_type: str = "dropdown" def __init__(self, options=[], value={'label': '', 'tooltip': '', 'value': ''}, **kwargs): super().__init__(**kwargs) - self.options: List[any] = options - self.value: dict = value + self.element = { + "options": options, + "value": value + } + + def to_dict(self): + return self._base_entity_element(**self.element) - def json(self): - node = self._base_blueprint() - node["options"] = self.options - node["value"] = self.value - return node class NumberInput(BaseInput): """ - The NumberInput class represents a whole number input node used + !!WORK_IN_PROGRESS!! The NumberInput class represents a whole number input node used in the OsintBuddy plugin system. value : int @@ -105,23 +101,22 @@ class NumberInput(BaseInput): class Plugin(OBPlugin): node = [NumberInput(value=10, placeholder='Enter a whole number')] """ - node_type: str = "number" + element_type: str = "number" def __init__(self, value=1, icon="123", **kwargs): super().__init__(**kwargs) - self.value: int = value - self.icon = icon + self.element = { + "value": value, + "icon": icon + } - def json(self): - node = self._base_blueprint() - node["value"] = self.value - node["icon"] = self.icon - return node + def to_dict(self): + return self._base_entity_element(**self.element) class DecimalInput(BaseInput): """ - The DecimalInput class represents a decimal number input node used + !!WORK_IN_PROGRESS!! The DecimalInput class represents a decimal number input node used in the OsintBuddy plugin system. value : float The float value stored in the node. @@ -130,15 +125,15 @@ class DecimalInput(BaseInput): class Plugin(OBPlugin): node = [DecimalInput(value=3.14, placeholder='Enter a decimal number')] """ - node_type: str = "decimal" + element_type: str = "decimal" def __init__(self, value=3.14, icon="123", **kwargs): super().__init__(**kwargs) - self.value: float = value - self.icon = icon - - def json(self): - node = self._base_blueprint() - node["value"] = self.value - node["icon"] = self.icon - return node + self.element = { + "value": value, + "icon": icon + } + + def to_dict(self): + return self._base_entity_element(**self.element) + diff --git a/src/osintbuddy/plugins.py b/src/osintbuddy/plugins.py index 286275f..b6293e2 100755 --- a/src/osintbuddy/plugins.py +++ b/src/osintbuddy/plugins.py @@ -29,7 +29,6 @@ def decorator(*a, **kwa): class OBAuthorUse(BaseModel): get_driver: Callable[[], None] - get_graph: Callable[[], None] class OBRegistry(type): @@ -52,8 +51,6 @@ def __init__(cls, name, bases, attrs): 'description': cls.description, 'author': cls.author }) - else: - OBRegistry.ui_labels.append(None) OBRegistry.labels.append(label) OBRegistry.plugins.append(cls) @@ -177,7 +174,7 @@ class OBPlugin(object, metaclass=OBRegistry): OBPlugin is the base class for all plugin classes in this application. It provides the required structure and methods for a plugin. """ - node: List[BaseElement] + entity: List[BaseElement] color: str = '#145070' label: str = '' icon: str = 'atom-2' @@ -203,13 +200,13 @@ def __call__(self): return self.blueprint() @staticmethod - def _map_graph_data_labels(element, kwargs): + def _map_graph_data_labels(element, **kwargs): label = to_snake_case(element['label']) - for passed_label in kwargs: - if passed_label == label: - if type(kwargs[label]) is str: + for element_key in kwargs.keys(): + if element_key == label: + if isinstance(kwargs[label], str): element['value'] = kwargs[label] - elif type(kwargs[label]) is dict: + elif isinstance(kwargs[label], dict): for t in kwargs[label]: element[t] = kwargs[label][t] return element @@ -221,23 +218,43 @@ def blueprint(cls, **kwargs): Includes label, name, color, icon, and a list of all elements for the node/plugin. """ - node = defaultdict(None) - node['label'] = cls.label - node['color'] = cls.color if cls.color else '#145070' - node['icon'] = cls.icon - node['elements'] = [] - for element in cls.node: - if isinstance(element, list): - node['elements'].append([ - cls._map_graph_data_labels(elm.json(), kwargs) - for elm in element - ]) - else: - element_row = cls._map_graph_data_labels(element.json(), kwargs) - node['elements'].append(element_row) - return node - - async def get_transform(self, transform_type: str, node, use: OBAuthorUse) -> Any: + entity_ui_node = defaultdict(None) + entity_ui_node['label'] = cls.label + entity_ui_node['color'] = cls.color if cls.color else '#145070' + entity_ui_node['icon'] = cls.icon + entity_ui_node['elements'] = [] + if cls.entity: + for element in cls.entity: + # if an entity element is a nested list, + # elements will be positioned next to each other horizontally + if isinstance(element, list): + entity_ui_node['elements'].append([ + cls._map_graph_data_labels(elm.to_dict(), **kwargs) + for elm in element + ]) + # otherwise position the entity elements vertically on the actual UI entity node + else: + element_row = cls._map_graph_data_labels(element.to_dict(), **kwargs) + entity_ui_node['elements'].append(element_row) + return entity_ui_node + if cls.node: + print("WARNING! Using node in plugins is being deprecated! Please switch to entity = [TextInput(...), ...] ") + for element in cls.node: + # if an entity element is a nested list, + # elements will be positioned next to each other horizontally + if isinstance(element, list): + row_elms = [] + for elm in element: + row_elms.append(cls._map_graph_data_labels(elm.to_dict(), **kwargs)) + entity_ui_node['elements'].append(row_elms) + # otherwise position the entity elements vertically on the actual UI entity node + else: + element_row = cls._map_graph_data_labels(element.to_dict(), **kwargs) + entity_ui_node['elements'].append(element_row) + return entity_ui_node + + + async def get_transform(self, transform_type: str, entity, use: OBAuthorUse) -> Any: """ Return output from a function accepting node data. The function will be called with a single argument, the node data from when a node context menu action is taken - and should return @@ -250,7 +267,7 @@ async def get_transform(self, transform_type: str, node, use: OBAuthorUse) -> An try: transform = await self.transforms[transform_type]( self=self, - node=self._map_to_transform_data(node), + node=self._map_to_transform_data(entity), use=use ) edge_label = self.transforms[transform_type].edge_label @@ -272,13 +289,13 @@ async def get_transform(self, transform_type: str, node, use: OBAuthorUse) -> An def _map_element(transform_map: dict, element: dict): label = to_snake_case(element.pop('label', None)) transform_map[label] = {} - type = element.pop('type', None) + element_type = element.pop('type', None) element.pop('icon', None) element.pop('placeholder', None) element.pop('style', None) element.pop('options', None) for k, v in element.items(): - if (isinstance(v, str) and len(element.values()) == 1) or type == 'dropdown': + if (isinstance(v, str) and len(element.values()) == 1) or element_type == 'dropdown': transform_map[label] = v else: transform_map[label][k] = v diff --git a/src/osintbuddy/utils/__init__.py b/src/osintbuddy/utils/__init__.py index e325784..28c3671 100644 --- a/src/osintbuddy/utils/__init__.py +++ b/src/osintbuddy/utils/__init__.py @@ -3,6 +3,7 @@ chunks, find_emails, to_clean_domain, + slugify, to_camel_case, to_snake_case, dkeys_to_snake_case