diff --git a/msp/fixtures/print_format.json b/msp/fixtures/print_format.json new file mode 100644 index 0000000..f0ab8cc --- /dev/null +++ b/msp/fixtures/print_format.json @@ -0,0 +1,29 @@ +[ + { + "absolute_value": 0, + "align_labels_right": 0, + "css": null, + "custom_format": 0, + "default_print_language": null, + "disabled": 0, + "doc_type": "MSP Documentation", + "docstatus": 0, + "doctype": "Print Format", + "font": "Default", + "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"
\\r\\n\\t
\\r\\n\\t\\t
\\r\\n\\t\\t\\t\\r\\n\\t\\t
\\r\\n\\t
\\r\\n\\t
\\r\\n\\t\\t

\\r\\nIT Documentation\\r\\n\\t\\t
{{ doc.name }}

\\r\\n\\t
\\r\\n\\t
\\r\\n\\t\\t\\r\\n\\t
\\r\\n
\\r\\n
\\r\\n\\t
\\r\\n\\t\\t
\\r\\n\\t
\\r\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"customer\", \"print_hide\": 0, \"label\": \"Customer\"}, {\"fieldname\": \"customer_name\", \"print_hide\": 0, \"label\": \"Customer Name\"}, {\"fieldname\": \"generation_date\", \"print_hide\": 0, \"label\": \"Generation Date\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"landscape\", \"print_hide\": 0, \"label\": \"Landscape\"}, {\"fieldname\": \"tactical_rmm_tenant_caption\", \"print_hide\": 0, \"label\": \"Tactical RMM Tenant Caption\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"

Introduction

\\n{{ frappe.utils.md_to_html(doc.introduction) }}\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Systems from RMM\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"

Server Systems

\\n{{ frappe.utils.md_to_html(doc.server_list) }}\\n
\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"

Workstation Systems

\\n{{ frappe.utils.md_to_html(doc.workstation_list) }}\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Backups\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"backup\", \"print_hide\": 0, \"label\": \"Backup\"}, {\"fieldname\": \"aditional_data\", \"print_hide\": 0, \"label\": \"Aditional Data\"}]", + "html": null, + "line_breaks": 0, + "modified": "2023-06-09 07:34:10.957905", + "module": "MSP", + "name": "Standard IT Landscape Documentation", + "parent": null, + "parentfield": null, + "parenttype": null, + "print_format_builder": 1, + "print_format_type": "Jinja", + "raw_commands": null, + "raw_printing": 0, + "show_section_headings": 1, + "standard": "No" + } +] \ No newline at end of file diff --git a/msp/hooked_methods.py b/msp/hooked_methods.py new file mode 100644 index 0000000..8b1c77b --- /dev/null +++ b/msp/hooked_methods.py @@ -0,0 +1,27 @@ +import frappe +from frappe.utils import cstr + +def build_full_location_path(doctype, method=None): + parent_location_name = doctype.parent_location + full_path = '' + html_full_path = '' + has_parent_location = True if parent_location_name else False + + while has_parent_location: + result = frappe.db.get_value('Location', {'name': parent_location_name}, ['name', 'location_name', 'parent_location'], as_dict=True) + if not result: + has_parent_location = False + continue + + full_path = f"{result['location_name']} --> {full_path}" + html_full_path = f"{result['location_name']} --> {html_full_path}" + parent_location_name = result['parent_location'] + + if not parent_location_name: + has_parent_location = False + + full_path = f"{full_path} {doctype.location_name}" if full_path != '' else doctype.location_name + html_full_path = f"{html_full_path} {doctype.location_name}" if html_full_path != '' else f"{doctype.location_name}" + + doctype.full_path = full_path + doctype.html_full_path = html_full_path \ No newline at end of file diff --git a/msp/hooks.py b/msp/hooks.py index 9fdebce..48b68d9 100644 --- a/msp/hooks.py +++ b/msp/hooks.py @@ -91,7 +91,7 @@ doctype_js = {"Location" : "public/js/location.js"} doc_events = { "Location": { - "before_save": "msp.tools.hooks_methods.build_full_location_path" + "before_save": "msp.hooked_methods.build_full_location_path" } } @@ -138,3 +138,7 @@ doc_events = { override_doctype_class = { "Location": "msp.overrides.location.CustomLocation.CustomLocation" } + +fixtures = [ + {"doctype": "Print Format", "filters": {"name": "Standard IT Landscape Documentation"}} +] diff --git a/msp/msp/doctype/it_landscape/it_landscape.js b/msp/msp/doctype/it_landscape/it_landscape.js index edfc078..c86a399 100644 --- a/msp/msp/doctype/it_landscape/it_landscape.js +++ b/msp/msp/doctype/it_landscape/it_landscape.js @@ -9,6 +9,9 @@ frappe.ui.form.on('IT Landscape', { }; if (frm.doc.monitoring_link) { frm.add_custom_button('Open Monitoring', () => frm.trigger('open_monitoring'), 'Actions'); + }; + if (frm.doc.rmm_instance) { + frm.add_custom_button('Get Agents From RMM', () => frm.trigger('rmm_get_agents'), 'RMM'); } }, open_ticket_system: function(frm) { @@ -17,6 +20,21 @@ frappe.ui.form.on('IT Landscape', { open_monitoring: function(frm) { window.open(frm.doc.monitoring_link, '_blank').focus(); }, + rmm_get_agents: function(frm) { + frappe.call({ + "method": "msp.tactical-rmm.get_agents", + args: { + "it_landscape": frm.doc.name, + "rmm_instance": frm.doc.rmm_instance, + "tactical_rmm_tenant_caption": frm.doc.tactical_rmm_tenant_caption + }, + callback: (response) => { + frappe.msgprint(__(response.message)); + } + + }) + }, + copy_ssh_keys: function(frm) { frappe.call({ diff --git a/msp/msp/doctype/it_landscape/it_landscape.json b/msp/msp/doctype/it_landscape/it_landscape.json index 77526a1..180470b 100644 --- a/msp/msp/doctype/it_landscape/it_landscape.json +++ b/msp/msp/doctype/it_landscape/it_landscape.json @@ -21,7 +21,8 @@ "landscape_image", "monitoring_link", "ticket_system_link", - "tactical_rmm_tenant_caption" + "tactical_rmm_tenant_caption", + "rmm_instance" ], "fields": [ { @@ -112,11 +113,17 @@ "fieldtype": "Link", "label": "IT Contract", "options": "IT Contract" + }, + { + "fieldname": "rmm_instance", + "fieldtype": "Link", + "label": "RMM Instance", + "options": "RMM Instance" } ], "image_field": "landscape_image", "links": [], - "modified": "2023-02-22 20:02:46.515700", + "modified": "2023-06-08 23:20:35.777651", "modified_by": "Administrator", "module": "MSP", "name": "IT Landscape", diff --git a/msp/msp/doctype/it_object/it_object.json b/msp/msp/doctype/it_object/it_object.json index 58f9c63..6381bb7 100644 --- a/msp/msp/doctype/it_object/it_object.json +++ b/msp/msp/doctype/it_object/it_object.json @@ -28,10 +28,15 @@ "linked_objects", "network_config_section", "ip_adresses", + "rmm_data_section", + "rmm_specs", + "rmm_software", "external_links_section", "admin_interface_link", "monitoring_link", - "oitc_host_uuid" + "oitc_host_uuid", + "rmm_agent_id", + "rmm_instance" ], "fields": [ { @@ -183,11 +188,38 @@ "fieldname": "serial_number", "fieldtype": "Data", "label": "Serial Number" + }, + { + "fieldname": "rmm_agent_id", + "fieldtype": "Data", + "label": "RMM Agent ID" + }, + { + "fieldname": "rmm_instance", + "fieldtype": "Link", + "label": "RMM Instance", + "options": "RMM Instance" + }, + { + "collapsible": 1, + "fieldname": "rmm_data_section", + "fieldtype": "Section Break", + "label": "RMM Data" + }, + { + "fieldname": "rmm_specs", + "fieldtype": "Markdown Editor", + "label": "RMM Specs" + }, + { + "fieldname": "rmm_software", + "fieldtype": "Markdown Editor", + "label": "RMM Software" } ], "image_field": "image", "links": [], - "modified": "2023-03-02 10:10:07.173113", + "modified": "2023-06-08 23:00:31.338542", "modified_by": "Administrator", "module": "MSP", "name": "IT Object", diff --git a/msp/msp/doctype/it_software_matching/__init__.py b/msp/msp/doctype/it_software_matching/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/msp/msp/doctype/it_software_matching/it_software_matching.js b/msp/msp/doctype/it_software_matching/it_software_matching.js new file mode 100644 index 0000000..c2bf0f9 --- /dev/null +++ b/msp/msp/doctype/it_software_matching/it_software_matching.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, itsdave GmbH and contributors +// For license information, please see license.txt + +frappe.ui.form.on('IT Software Matching', { + // refresh: function(frm) { + + // } +}); diff --git a/msp/msp/doctype/it_software_matching/it_software_matching.json b/msp/msp/doctype/it_software_matching/it_software_matching.json new file mode 100644 index 0000000..a148241 --- /dev/null +++ b/msp/msp/doctype/it_software_matching/it_software_matching.json @@ -0,0 +1,70 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "ITSWMATCH-.#####", + "creation": "2023-06-08 22:10:40.703139", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "search_regex", + "software_name", + "category", + "active" + ], + "fields": [ + { + "fieldname": "search_regex", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Search Regex" + }, + { + "fieldname": "software_name", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Software Name" + }, + { + "fieldname": "category", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Category", + "options": "\nSoftware\nMS Office" + }, + { + "default": "0", + "fieldname": "active", + "fieldtype": "Check", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Active" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2023-06-08 22:10:59.456228", + "modified_by": "Administrator", + "module": "MSP", + "name": "IT Software Matching", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC" +} \ No newline at end of file diff --git a/msp/msp/doctype/it_software_matching/it_software_matching.py b/msp/msp/doctype/it_software_matching/it_software_matching.py new file mode 100644 index 0000000..980eb79 --- /dev/null +++ b/msp/msp/doctype/it_software_matching/it_software_matching.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, itsdave GmbH and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class ITSoftwareMatching(Document): + pass diff --git a/msp/msp/doctype/it_software_matching/test_it_software_matching.py b/msp/msp/doctype/it_software_matching/test_it_software_matching.py new file mode 100644 index 0000000..127dff4 --- /dev/null +++ b/msp/msp/doctype/it_software_matching/test_it_software_matching.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, itsdave GmbH and Contributors +# See license.txt + +# import frappe +import unittest + +class TestITSoftwareMatching(unittest.TestCase): + pass diff --git a/msp/msp/doctype/msp_documentation/msp_documentation.js b/msp/msp/doctype/msp_documentation/msp_documentation.js index e1ba6c0..313c602 100644 --- a/msp/msp/doctype/msp_documentation/msp_documentation.js +++ b/msp/msp/doctype/msp_documentation/msp_documentation.js @@ -14,6 +14,16 @@ frappe.ui.form.on('MSP Documentation', { } }); }, 'Workflow'); + frm.add_custom_button('2. office suche', function(){ + frappe.call({ + method: 'msp.tactical-rmm.search_office', + args: { documentation: frm.doc.name }, + callback:function(r){ + console.log(r.message) + frm.reload_doc() + } + }); + }, 'Workflow'); } }); diff --git a/msp/msp/doctype/msp_documentation/msp_documentation.json b/msp/msp/doctype/msp_documentation/msp_documentation.json index 7809efb..5aaab09 100644 --- a/msp/msp/doctype/msp_documentation/msp_documentation.json +++ b/msp/msp/doctype/msp_documentation/msp_documentation.json @@ -9,9 +9,12 @@ "field_order": [ "landscape", "customer", + "customer_name", "tactical_rmm_tenant_caption", "generation_date", "introduction", + "server_list", + "workstation_list", "system_list", "backup", "aditional_data" @@ -24,10 +27,12 @@ "options": "IT Landscape" }, { + "fetch_from": "landscape.customer", "fieldname": "customer", "fieldtype": "Link", "label": "Customer", - "options": "Customer" + "options": "Customer", + "read_only": 1 }, { "fieldname": "introduction", @@ -59,11 +64,28 @@ "fieldname": "generation_date", "fieldtype": "Date", "label": "Generation Date" + }, + { + "fieldname": "server_list", + "fieldtype": "Markdown Editor", + "label": "Server List" + }, + { + "fieldname": "workstation_list", + "fieldtype": "Markdown Editor", + "label": "Workstation List" + }, + { + "fetch_from": "customer.customer_name", + "fieldname": "customer_name", + "fieldtype": "Data", + "label": "Customer Name", + "read_only": 1 } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-02-02 01:08:47.664035", + "modified": "2023-06-09 07:14:25.256192", "modified_by": "Administrator", "module": "MSP", "name": "MSP Documentation", diff --git a/msp/msp/doctype/msp_functions/__init__.py b/msp/msp/doctype/msp_functions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/msp/msp/doctype/msp_functions/msp_functions.js b/msp/msp/doctype/msp_functions/msp_functions.js new file mode 100644 index 0000000..418b0b1 --- /dev/null +++ b/msp/msp/doctype/msp_functions/msp_functions.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, itsdave GmbH and contributors +// For license information, please see license.txt + +frappe.ui.form.on('MSP Functions', { + // refresh: function(frm) { + + // } +}); diff --git a/msp/msp/doctype/msp_functions/msp_functions.json b/msp/msp/doctype/msp_functions/msp_functions.json new file mode 100644 index 0000000..11abc23 --- /dev/null +++ b/msp/msp/doctype/msp_functions/msp_functions.json @@ -0,0 +1,41 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-06-08 21:34:09.516160", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "get_office_versions" + ], + "fields": [ + { + "fieldname": "get_office_versions", + "fieldtype": "Button", + "label": "Get Office Versions", + "options": "msp.tactical-rmm.search_office" + } + ], + "index_web_pages_for_search": 1, + "issingle": 1, + "links": [], + "modified": "2023-06-08 21:34:09.516160", + "modified_by": "Administrator", + "module": "MSP", + "name": "MSP Functions", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC" +} \ No newline at end of file diff --git a/msp/msp/doctype/msp_functions/msp_functions.py b/msp/msp/doctype/msp_functions/msp_functions.py new file mode 100644 index 0000000..d3ccc12 --- /dev/null +++ b/msp/msp/doctype/msp_functions/msp_functions.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, itsdave GmbH and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class MSPFunctions(Document): + pass diff --git a/msp/msp/doctype/msp_functions/test_msp_functions.py b/msp/msp/doctype/msp_functions/test_msp_functions.py new file mode 100644 index 0000000..a72b6ed --- /dev/null +++ b/msp/msp/doctype/msp_functions/test_msp_functions.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, itsdave GmbH and Contributors +# See license.txt + +# import frappe +import unittest + +class TestMSPFunctions(unittest.TestCase): + pass diff --git a/msp/msp/doctype/rmm_instance/__init__.py b/msp/msp/doctype/rmm_instance/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/msp/msp/doctype/rmm_instance/rmm_instance.js b/msp/msp/doctype/rmm_instance/rmm_instance.js new file mode 100644 index 0000000..a2da5c2 --- /dev/null +++ b/msp/msp/doctype/rmm_instance/rmm_instance.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, itsdave GmbH and contributors +// For license information, please see license.txt + +frappe.ui.form.on('RMM Instance', { + // refresh: function(frm) { + + // } +}); diff --git a/msp/msp/doctype/rmm_instance/rmm_instance.json b/msp/msp/doctype/rmm_instance/rmm_instance.json new file mode 100644 index 0000000..aed07e1 --- /dev/null +++ b/msp/msp/doctype/rmm_instance/rmm_instance.json @@ -0,0 +1,76 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "format:RMMINST-{caption}", + "creation": "2023-06-08 22:46:28.727092", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "caption", + "type", + "api_url", + "user", + "key" + ], + "fields": [ + { + "fieldname": "type", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Type", + "options": "Tactical RMM", + "reqd": 1 + }, + { + "fieldname": "api_url", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "API URL", + "reqd": 1 + }, + { + "fieldname": "caption", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Caption", + "reqd": 1 + }, + { + "fieldname": "user", + "fieldtype": "Data", + "label": "User" + }, + { + "fieldname": "key", + "fieldtype": "Password", + "label": "Key" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2023-06-08 22:48:17.914520", + "modified_by": "Administrator", + "module": "MSP", + "name": "RMM Instance", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC" +} \ No newline at end of file diff --git a/msp/msp/doctype/rmm_instance/rmm_instance.py b/msp/msp/doctype/rmm_instance/rmm_instance.py new file mode 100644 index 0000000..52848c3 --- /dev/null +++ b/msp/msp/doctype/rmm_instance/rmm_instance.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, itsdave GmbH and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class RMMInstance(Document): + pass diff --git a/msp/msp/doctype/rmm_instance/test_rmm_instance.py b/msp/msp/doctype/rmm_instance/test_rmm_instance.py new file mode 100644 index 0000000..bbe8c34 --- /dev/null +++ b/msp/msp/doctype/rmm_instance/test_rmm_instance.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, itsdave GmbH and Contributors +# See license.txt + +# import frappe +import unittest + +class TestRMMInstance(unittest.TestCase): + pass diff --git a/msp/quotation_tools.py b/msp/quotation_tools.py new file mode 100644 index 0000000..84d2bcb --- /dev/null +++ b/msp/quotation_tools.py @@ -0,0 +1,59 @@ + +import frappe + +@frappe.whitelist() +def copy_attachments(source_doctype, source_docname, target_doctype, target_docname): + attachments = frappe.get_all("File", filters={"attached_to_doctype": source_doctype, "attached_to_name": source_docname}) + + for attachment in attachments: + # Überprüfen Sie den Datei-URL-Wert + file_url = frappe.db.get_value("File", attachment.name, "file_url") + + # Überprüfen, ob ein Anhang mit derselben URL bereits für das Ziel-Dokument existiert + exists = frappe.db.exists({ + "doctype": "File", + "file_url": file_url, + "attached_to_doctype": target_doctype, + "attached_to_name": target_docname + }) + + if not exists: + # Wenn nicht existiert, dann Anhang zum Ziel-Dokument kopieren + attach = frappe.get_doc({ + "doctype": "File", + "file_url": file_url, + "attached_to_doctype": target_doctype, + "attached_to_name": target_docname + }) + attach.insert(ignore_permissions=True) + +""" Benötigt das folgende Client Script für Quotation Form + +frappe.ui.form.on('Quotation', { + refresh: function(frm) { + frm.add_custom_button(__('Anhänge hinzufügen'), function() { + attach_item_attachments_to_quotation(frm); + }, "Aktionen"); + } +}); + +function attach_item_attachments_to_quotation(frm) { + frm.doc.items.forEach(item_row => { + frappe.call({ + method: 'msp.quotation_tools.copy_attachments', + args: { + 'source_doctype': 'Item', + 'source_docname': item_row.item_code, // Verwenden Sie item_code, um den Anhang vom Artikel zu kopieren + 'target_doctype': 'Quotation', + 'target_docname': frm.doc.name + }, + callback: function(response) { + if (!response.exc) { + frm.reload_doc(); + } + } + }); + }); + frappe.msgprint(__('Anhänge wurden hinzugefügt.')); +} + """ \ No newline at end of file diff --git a/msp/tactical-rmm.py b/msp/tactical-rmm.py index a7294ee..de743bc 100644 --- a/msp/tactical-rmm.py +++ b/msp/tactical-rmm.py @@ -4,6 +4,84 @@ from frappe.utils.password import get_decrypted_password import requests import json from pprint import pprint +import re + +@frappe.whitelist() +def get_agents(it_landscape, rmm_instance = None, tactical_rmm_tenant_caption = None): + pass + + +@frappe.whitelist() +def get_relevant_software_for_agent(agent_id): + found_software = [] + software_for_agent = get_software_for_agent(agent_id) + if "software" in software_for_agent: + for s in software_for_agent["software"]: + result = _match_software(s) + if result: + found_software.append(result) + + return(found_software) + +def _match_software(rmm_software_elememt): + sw_match_list = frappe.get_all("IT Software Matching", fields=["search_regex", "software_name", "category"], filters={"active": 1}) + for el in sw_match_list: + result = re.match(el["search_regex"]) + if result: + return {el["software_name"], el["category"]} + return None + +@frappe.whitelist() +def search_office(agents = None): + points_for_found_strings = {} + agents_with_office = [] + + if not agents: + agents = get_all_agents() + todo = len(agents) + count = 0 + for agent in agents: + found_office = False + count = count + 1 + print("verarbeite agent " + str(count) + " von " + str(todo)) + software_for_agent = get_software_for_agent(agent["agent_id"]) + if "software" in software_for_agent: + for s in software_for_agent["software"]: + if (s["name"].lower().startswith("Microsoft Office".lower())): + found_string = s["name"] + found_office = True + + if found_string in points_for_found_strings.keys(): + points_for_found_strings[found_string] = points_for_found_strings[found_string] + 1 + else: + points_for_found_strings[found_string] = 1 + if found_office: + agents_with_office.append(agent) + else: + pass + + + + print(points_for_found_strings) + #print(len(agents_with_office)) + search_for_office_patches(agents_with_office) + print(points_for_found_strings) + +def search_for_office_patches(agents_with_office): + count = 0 + for agent in agents_with_office: + found_patches_for_office = False + patches = get_patches_for_agent(agent["agent_id"]) + for patch in patches: + if "office".lower() in patch["title"].lower(): + found_patches_for_office = True + if found_patches_for_office == False: + print("kein patch für agent mit office gefunden: " + agent["hostname"] + " | " + agent["client_name"]) + count = count + 1 + print("Anzahl Clients: " + str(count)) + + + @frappe.whitelist() def get_agents_pretty(documentation): @@ -15,15 +93,30 @@ def get_agents_pretty(documentation): client_name = documentation_doc.tactical_rmm_tenant_caption agents = get_all_agents() - + print(agents) agent_list = [] + workstation_list = [] + server_list = [] + #if not agent_list: + # frappe.throw("API Abfrage hat keine Agents geliefert.") + + for agent in agents: if agent["client_name"] == client_name: agent_list.append(agent) + if agent["monitoring_type"] == "workstation": + workstation_list.append(agent) + if agent["monitoring_type"] == "server": + server_list.append(agent) + pprint(agent) output = make_agent_md_output(agent_list) + output_workstation = make_agent_md_output(workstation_list) + output_server = make_agent_md_output(server_list) documentation_doc.system_list = output + documentation_doc.workstation_list = output_workstation + documentation_doc.server_list = output_server documentation_doc.save() return agent_list @@ -42,9 +135,48 @@ def get_all_agents(): } agents = requests.get(f"{API}/agents/?detail=true", headers=HEADERS) - return agents.json() +def get_software_for_agent(agent_id=None): + settings = frappe.get_single("MSP Settings") + if not settings.api_key: + frappe.throw("API Key is missing") + if not settings.api_url: + frappe.throw("API URL is missing") + + API = settings.api_url + HEADERS = { + "Content-Type": "application/json", + "X-API-KEY": get_decrypted_password("MSP Settings", "MSP Settings", "api_key", raise_exception=True), + } + + if not agent_id: + frappe.throw("Agent ID fehlt") + + software_for_agent = requests.get(f"{API}/software/{agent_id}/", headers=HEADERS) + return software_for_agent.json() + +def get_patches_for_agent(agent_id=None): + settings = frappe.get_single("MSP Settings") + if not settings.api_key: + frappe.throw("API Key is missing") + if not settings.api_url: + frappe.throw("API URL is missing") + + API = settings.api_url + HEADERS = { + "Content-Type": "application/json", + "X-API-KEY": get_decrypted_password("MSP Settings", "MSP Settings", "api_key", raise_exception=True), + } + + if not agent_id: + frappe.throw("Agent ID fehlt") + + patches_for_agent = requests.get(f"{API}/winupdate/{agent_id}/", headers=HEADERS) + return patches_for_agent.json() + + + def make_agent_md_output(agents): md_output = "" @@ -56,8 +188,12 @@ def make_agent_md_output(agents): - GPU: {agent["graphics"]} - Disks: {agent["physical_disks"]} - Model: {render_model(agent["make_model"])} +- Serial Number: {agent["serial_number"]} - Type: {agent["monitoring_type"]} - Site: {agent["site_name"]} +- Local IPs: {agent["local_ips"]} +- Public IP: {agent["public_ip"]} +- Last Seen: {agent["last_seen"]} - Last User: {agent["logged_username"]} ''' if agent["description"]: