From d7858c6042506d0a506c638db12bd29d150f4a31 Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Sat, 7 Dec 2024 19:25:07 +1100 Subject: [PATCH] GraphQL Settings --- docs/DEVICE_MANAGEMENT.md | 12 +- docs/NETWORK_TREE.md | 2 +- front/settings.php | 158 +++++++++++++++--------- server/graphql_server/graphql_schema.py | 47 +++++++ 4 files changed, 154 insertions(+), 65 deletions(-) diff --git a/docs/DEVICE_MANAGEMENT.md b/docs/DEVICE_MANAGEMENT.md index 2b205cc52..ab099b1e8 100755 --- a/docs/DEVICE_MANAGEMENT.md +++ b/docs/DEVICE_MANAGEMENT.md @@ -5,7 +5,7 @@ The Main Info section is where most of the device identifyiable information is s > [!NOTE] > -> You can multi-edit devices by selecting them in the main Devices view, from the Mainetence section, or via the CSV Export fucntionality under Maintenance. More info can be found in the [Devices Bulk-editing docs](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md). +> You can multi-edit devices by selecting them in the main Devices view, from the Mainetence section, or via the CSV Export functionality under Maintenance. More info can be found in the [Devices Bulk-editing docs](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md). ![Main Info](/docs/img/DEVICE_MANAGEMENT/DeviceManagement_MainInfo.png) @@ -32,12 +32,18 @@ The Main Info section is where most of the device identifyiable information is s ## Dummy devices -You can create dummy devices from the Devices listing screen. The **MAC** field and the **Last IP** field will then become editable. +You can create dummy devices from the Devices listing screen. ![Create Dummy Device](/docs/img/DEVICE_MANAGEMENT/Devices_CreateDummyDevice.png) + +The **MAC** field and the **Last IP** field will then become editable. + ![Save Dummy Device](/docs/img/DEVICE_MANAGEMENT/DeviceEdit_SaveDummyDevice.png) -You can couple this with the `ICMP` plugin which can be used to monitor the status of these devices, if they are actual devices reachable with the ping command. + +> [!NOTE] +> +> You can couple this with the `ICMP` plugin which can be used to monitor the status of these devices, if they are actual devices reachable with the `ping` command. If not, you can use a loopback IP address so they appear online, such as `0.0.0.0` or `127.0.0.1`. ## Copying data from an existing device. diff --git a/docs/NETWORK_TREE.md b/docs/NETWORK_TREE.md index 91ed85d81..5dbafca0e 100755 --- a/docs/NETWORK_TREE.md +++ b/docs/NETWORK_TREE.md @@ -2,7 +2,7 @@ Make sure you have a root device with the MAC `Internet` (No other MAC addresses are currently supported as the root node) set to a network device type (e.g.: **Type**:`Router`). -> 💡 Tip: You can add dummy devices via the [Undiscoverables plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/undiscoverables/README.md) +> 💡 Tip: You can add dummy devices via the [Create dummy device](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICE_MANAGEMENT.md#dummy-devices) button in the Devices listing page. > 💡 Tip: Export your configuration of the Network and Devices once in a while via the Export CSV feature under **Maintenance** -> **Backup/Restore** -> **CSV Export**. diff --git a/front/settings.php b/front/settings.php index 9ee826913..bd919c8ba 100755 --- a/front/settings.php +++ b/front/settings.php @@ -177,69 +177,105 @@ function getData(){ console.log("in getData"); - $.get('api/table_settings.json?nocache=' + Date.now(), function(res) { - - settingsData = res["data"]; - - // Wrong number of settings processing - if(settingsNumberDB != settingsData.length) - { - showModalOk('WARNING', ""); - setTimeout(() => { - clearCache() - }, 3000); - } else - { - $.get('api/plugins.json?nocache=' + Date.now(), function(res) { - - pluginsData = res["data"]; - - // Sort settingsData alphabetically based on the "setGroup" property - settingsData.sort((a, b) => { - if (a["setGroup"] < b["setGroup"]) { - return -1; - } - if (a["setGroup"] > b["setGroup"]) { - return 1; - } - return 0; - }); - - exception_occurred = false; - - // check if cache needs to be refreshed - // the getSetting method returns an empty string even if a setting is not found - // however, __metadata needs to be always a JSON object - // let's use that to verify settings were initialized correctly - settingsData.forEach((set) => { - - setKey = set['setKey'] - - try { - const isMetadata = setKey.includes('__metadata'); - // if this isn't a metadata entry, get corresponding metadata object from the dummy setting - const setObj = isMetadata ? {} : JSON.parse(getSetting(`${setKey}__metadata`)); - - } catch (error) { - console.error(`Error getting setting for ${setKey}:`, error); - showModalOk('WARNING', "Outdated cache - refreshing (refresh browser cache if needed)"); - - setTimeout(() => { - clearCache() - }, 3000); - - exception_occurred = true; + // get settings from the secured graphql endpoint + $.ajax({ + url: "/php/server/query_graphql.php", // Replace with your GraphQL endpoint + method: "POST", + contentType: "application/json", + data: JSON.stringify({ + query: ` + query { + settings { + settings { + setKey + setName + setDescription + setOptions + setGroup + setType + setValue + setEvents + setOverriddenByEnv + } + count + } } - }); - - // only proceed if everything was loaded correctly - if(!exception_occurred) - { - initSettingsPage(settingsData, pluginsData); + ` + }), + success: function (response) { + console.log("Response:", response); + + // Handle the successful response + if (response && response.settings) { + const settingsData = response.settings.settings; + console.log("Settings:", settingsData); + + // Wrong number of settings processing + if(settingsNumberDB != settingsData.length) + { + showModalOk('WARNING', ""); + setTimeout(() => { + clearCache() + }, 3000); + } else + { + $.get('api/plugins.json?nocache=' + Date.now(), function(res) { + + pluginsData = res["data"]; + + // Sort settingsData alphabetically based on the "setGroup" property + settingsData.sort((a, b) => { + if (a["setGroup"] < b["setGroup"]) { + return -1; + } + if (a["setGroup"] > b["setGroup"]) { + return 1; + } + return 0; + }); + + exception_occurred = false; + + // check if cache needs to be refreshed + // the getSetting method returns an empty string even if a setting is not found + // however, __metadata needs to be always a JSON object + // let's use that to verify settings were initialized correctly + settingsData.forEach((set) => { + + setKey = set['setKey'] + + try { + const isMetadata = setKey.includes('__metadata'); + // if this isn't a metadata entry, get corresponding metadata object from the dummy setting + const setObj = isMetadata ? {} : JSON.parse(getSetting(`${setKey}__metadata`)); + + } catch (error) { + console.error(`Error getting setting for ${setKey}:`, error); + showModalOk('WARNING', "Outdated cache - refreshing (refresh browser cache if needed)"); + + setTimeout(() => { + clearCache() + }, 3000); + + exception_occurred = true; + } + }); + + // only proceed if everything was loaded correctly + if(!exception_occurred) + { + initSettingsPage(settingsData, pluginsData); + } + }) + } + } - }) - } - }) + }, + error: function (xhr, status, error) { + console.error("Error:", error); + // Handle any errors + } + }); } // ------------------------------------------------------------------- diff --git a/server/graphql_server/graphql_schema.py b/server/graphql_server/graphql_schema.py index 5b57936ed..0816644d5 100755 --- a/server/graphql_server/graphql_schema.py +++ b/server/graphql_server/graphql_schema.py @@ -14,11 +14,13 @@ # Define a base URL with the user's home directory folder = apiPath +# --- DEVICES --- # Pagination and Sorting Input Types class SortOptionsInput(InputObjectType): field = String() order = String() + class PageQueryOptionsInput(InputObjectType): page = Int() limit = Int() @@ -26,6 +28,7 @@ class PageQueryOptionsInput(InputObjectType): search = String() status = String() + # Device ObjectType class Device(ObjectType): rowid = Int() @@ -70,8 +73,30 @@ class DeviceResult(ObjectType): devices = List(Device) count = Int() + +# --- SETTINGS --- + +# Setting ObjectType +class Setting(ObjectType): + setKey = String() + setName = String() + setDescription = String() + setType = String() + setOptions = String() + setGroup = String() + setValue = String() + setEvents = String() + setOverriddenByEnv = Boolean() + + +class SettingResult(ObjectType): + settings = List(Setting) + count = Int() + # Define Query Type with Pagination Support class Query(ObjectType): + + # --- DEVICES --- devices = Field(DeviceResult, options=PageQueryOptionsInput()) def resolve_devices(self, info, options=None): @@ -175,6 +200,28 @@ def resolve_devices(self, info, options=None): return DeviceResult(devices=devices, count=total_count) + # --- SETTINGS --- + settings = Field(SettingResult) + + def resolve_settings(root, info): + + try: + with open(folder + 'table_settings.json', 'r') as f: + settings_data = json.load(f)["data"] + except (FileNotFoundError, json.JSONDecodeError) as e: + mylog('none', f'[graphql_schema] Error loading settings data: {e}') + return SettingResult(settings=[], count=0) + + + mylog('none', f'[graphql_schema] settings_data: {settings_data}') + + # # Convert to Setting objects + settings = [Setting(**setting) for setting in settings_data] + + return SettingResult(settings=settings, count=len(settings)) + + + # helps sorting inconsistent dataset mixed integers and strings def mixed_type_sort_key(value): if value is None or value == "":