From 2ee6bd3bb666cb19a2b98d0b0fdf3441cb8d2b1e Mon Sep 17 00:00:00 2001 From: Brian Read Date: Thu, 12 Sep 2024 18:54:38 +0100 Subject: [PATCH] Add in preformat and sm1 html to json5 extractor program --- Templates/html_controls.html.ep.xml | 7 + html/CreateStarterWebsite.html | 102 +++++++++++ html/DiskUsage.html | 93 ++++++++++ json5/CreateStarterWebsite.json5 | 61 +++++++ json5/DiskUsage.json5 | 47 +++++ json5/nfsshare.json5 | 147 ++++++++++++++++ sm1-html-2-json5.py | 261 ++++++++++++++++++++++++++++ 7 files changed, 718 insertions(+) create mode 100644 html/CreateStarterWebsite.html create mode 100644 html/DiskUsage.html create mode 100644 json5/CreateStarterWebsite.json5 create mode 100644 json5/DiskUsage.json5 create mode 100644 json5/nfsshare.json5 create mode 100644 sm1-html-2-json5.py diff --git a/Templates/html_controls.html.ep.xml b/Templates/html_controls.html.ep.xml index fd7af4f..9d31aa9 100644 --- a/Templates/html_controls.html.ep.xml +++ b/Templates/html_controls.html.ep.xml @@ -118,4 +118,11 @@ ]]> + + ${value}' + + ]]> + + diff --git a/html/CreateStarterWebsite.html b/html/CreateStarterWebsite.html new file mode 100644 index 0000000..75db8ef --- /dev/null +++ b/html/CreateStarterWebsite.html @@ -0,0 +1,102 @@ + + + + +SME Server sme11.thereadclan.me.uk + + + + + + + +
+ Warning: a reconfigure and reboot is required before proceeding! Failure to do so now + may leave your system in an unknown state!
+ URGENT NOTICE: As per June 30th 2024, SME Server 10 is obsolete, and potentially INSECURE. NO support will be offered for any issue found with this installed version. + Please migrate IMMEDIATELY to Koozali SME Server 11 or higher version. Failure to upgrade may lead to the compromise of this server. +
Please, consult https://wiki.koozali.org/SME_Server:Download to get last available version.
+

Create a starter website

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ To create a simple web page for your company, fill + in the fields below and click on Create. +

+

+ You can leave any field blank if you do not need it. +

+

+ The text that you enter below will be line wrapped + for a nicer appearance in your web page. Leave a blank line + whenever you want to start a new paragraph. If you need + to force a line break without starting a new paragraph (for + example after each line of a mailing address), then type + the four-character sequence +

<BR>
+ where you would like each line break. +

+

+ Do not use this option + if you have already customized your web site, since it will + overwrite the "index.htm" file in your web site directory. +

Company name +

First header, typically used for short phrases such + as "Leader in the field of textile manufacturing"

+

Text following first header, typically used for a + paragraph of marketing information.

+

Second header, typically used for short phrases such + as "For more information" or "To order our products":

+

Text following second header, typically used for contact + or ordering information:

+

When you create this web page, the file + "index.htm" will be overwritten + in your web site directory.

+

Do you wish to proceed?

+
+ +
+ +
+ + SME Server 11.0.0
Copyright 1999-2006 Mitel Corporation
All rights reserved. + +
Copyright (c) 2013 - 2021 Koozali Foundation Inc.
+
+ + + + diff --git a/html/DiskUsage.html b/html/DiskUsage.html new file mode 100644 index 0000000..e089d46 --- /dev/null +++ b/html/DiskUsage.html @@ -0,0 +1,93 @@ + + + + + SME Server sme10.thereadclan.me.uk + + + + + + + + +

Disk usage

+
+ + + + + +

  +

+

Wed Sep 11 19:01:00 BST 2024 +

+

Filesystem             Size  Used Avail Use% Mounted on
+/dev/mapper/main-root   29G  4.8G   24G  17% /
+devtmpfs               2.0G     0  2.0G   0% /dev
+tmpfs                  2.0G   12K  2.0G   1% /dev/shm
+tmpfs                  2.0G     0  2.0G   0% /sys/fs/cgroup
+tmpfs                  2.0G  648K  2.0G   1% /run
+/dev/sda1              497M  111M  386M  23% /boot
+

+
+ + + + + + + + + + + + + + + + + + + + +
I-baysUsagePath
Primary4.0K/home/e-smith/files/ibays/Primary
anibay4.0K/home/e-smith/files/ibays/anibay
opt410M/opt
+

  +

+ + + + + + + + + + + + + + + + +
UsersUsagePath
root2.1M/root
brianr16K/home/e-smith/files/users/brianr
+ + +
+ +
+ + SME Server 10.1 +
Copyright 1999-2006 Mitel Corporation +
All rights reserved. + +
Copyright (c) 2013 - 2021 Koozali Foundation Inc. +
+
+ + + diff --git a/json5/CreateStarterWebsite.json5 b/json5/CreateStarterWebsite.json5 new file mode 100644 index 0000000..e75fb59 --- /dev/null +++ b/json5/CreateStarterWebsite.json5 @@ -0,0 +1,61 @@ +{ + 'PackageName': 'CreateStarterWebsite', + 'prefix': 'CSW', + 'MenuHeading': 'Miscellaneous', + 'MenuDescription': 'Create Starter Website', + 'MenuNavigation': '2000 400', + 'firstPanel': 'PARAMS', + 'signalEvent': 'smeserver-createstarterwebsite-update', + 'html': { + 'Name': 'params', + 'route': 'PARAMS', + 'Header': 'Create a starter website', + 'SubHeader': 'Manage CreateStarterWebsite settings:', + 'Paragraph1': 'To create a simple web page for your company, fill \n\t in the fields below and click onCreate.', + 'Paragraph2': 'You can leave any field blank if you do not need it.', + 'Paragraph3': 'The text that you enter below will be line wrapped \n\t for a nicer appearance in your web page. Leave a blank line \n\t whenever you want to start a new paragraph. If you need \n\t to force a line break without starting a new paragraph (for \n\t example after each line of a mailing address), then type \n\t the four-character sequence', + 'Paragraph4': 'Do not use this optionif you have already customized your web site, since it will \n\t overwrite the \'index.htm\' file in your web site directory.', + 'Input1': { + 'Type': 'Text', + 'Value': '', + 'Name': 'companyName', + 'Label': null + }, + 'Paragraph5': 'First header, typically used for short phrases such \n\t as \'Leader in the field of textile manufacturing\'', + 'Input2': { + 'Type': 'Text', + 'Value': '', + 'Name': 'header1', + 'Label': null + }, + 'Paragraph6': 'Text following first header, typically used for a \n\t paragraph of marketing information.', + 'Input3': { + 'Type': 'Textarea', + 'Value': '', + 'Name': 'text1', + 'Label': null + }, + 'Paragraph7': 'Second header, typically used for short phrases such \n\t as \'For more information\' or \'To order our products\':', + 'Input4': { + 'Type': 'Text', + 'Value': '', + 'Name': 'header2', + 'Label': null + }, + 'Paragraph8': 'Text following second header, typically used for contact \n\t or ordering information:', + 'Input5': { + 'Type': 'Textarea', + 'Value': '', + 'Name': 'text2', + 'Label': null + }, + 'Paragraph9': 'When you create this web page, the file\n\t \'index.htm\' will be overwritten\n\t in your web site directory.', + 'Paragraph10': 'Do you wish to proceed?', + 'Input6': { + 'Type': 'Submit', + 'Value': 'Create', + 'Name': 'Next', + 'Label': null + } + } +} \ No newline at end of file diff --git a/json5/DiskUsage.json5 b/json5/DiskUsage.json5 new file mode 100644 index 0000000..bb6c1f3 --- /dev/null +++ b/json5/DiskUsage.json5 @@ -0,0 +1,47 @@ +{ + 'PackageName': 'DiskUsage', + 'prefix': 'DU', + 'MenuHeading': 'Miscellaneous', + 'MenuDescription': 'Disk Usage', + 'MenuNavigation': '2000 400', + 'firstPanel': 'PARAMS', + 'signalEvent': 'smeserver-diskusage-update', + 'html': { + 'Name': 'params', + 'route': 'PARAMS', + 'Header': 'Disk usage', + 'SubHeader': 'Manage DiskUsage settings:', + 'Paragraph1': ' ', + 'Paragraph2': 'Wed Sep 11 19:01:00 BST 2024', + 'Preformatted1': 'Filesystem Size Used Avail Use% Mounted on\n/dev/mapper/main-root 29G 4.8G 24G 17% /\ndevtmpfs 2.0G 0 2.0G 0% /dev\ntmpfs 2.0G 12K 2.0G 1% /dev/shm\ntmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup\ntmpfs 2.0G 648K 2.0G 1% /run\n/dev/sda1 497M 111M 386M 23% /boot', + 'Table1': { + 'Type': 'Table', + 'TableControl': 'Table1', + 'TopHeadings': [ + 'I-bays', + 'Usage', + 'Path' + ], + 'Columns': [ + 'Table1-I-bays', + 'Table1-Usage', + 'Table1-Path' + ] + }, + 'Paragraph3': ' ', + 'Table2': { + 'Type': 'Table', + 'TableControl': 'Table2', + 'TopHeadings': [ + 'Users', + 'Usage', + 'Path' + ], + 'Columns': [ + 'Table2-Users', + 'Table2-Usage', + 'Table2-Path' + ] + } + } +} \ No newline at end of file diff --git a/json5/nfsshare.json5 b/json5/nfsshare.json5 new file mode 100644 index 0000000..e3eb3b6 --- /dev/null +++ b/json5/nfsshare.json5 @@ -0,0 +1,147 @@ +{ + PackageName: 'Nfsshare', + prefix: 'nfs', + MenuHeading: 'Network', + MenuDescription: 'NFS data share', + MenuNavigation: '2000 400', + firstPanel: 'TABLE', + signalEvent: 'smeserver-nfsshare-update', + html: [ + { + Name: 'params', + route: 'PARAMS', + Header: 'NFS Share Contrib', + SubHeader: 'Manage NFS Ibay settings:', + Paragraph1: 'These parameters will be effective only if the share is enabled. The share is in /home/e-smith/files/ibays//files', + Input1: { + Name: 'IbayName', + Type: 'Text', + Label: 'Information Bay name', + Value: 'stash("IbayName")', + }, + Input2: { + Name: 'ShareOwnerGrp', + Type: 'Selection', + Label: 'Share owner Group', + Value: [ + 'Write = admin, Read = group', + 'Write = group, Read = everyone', + 'Write = group, Read = group', + ], + Default: 0, + }, + Input3: { + Name: 'EnableNFSshare', + Type: 'Selection', + Label: 'Enable the NFS Share', + Value: [ + 'Disabled', + 'Enabled', + ], + Default: 0, + }, + Input4: { + Name: 'ShareOnLocalNetwork', + Type: 'Selection', + Label: 'EnableShare on local network', + Value: [ + 'Disabled', + 'Enabled', + ], + Default: 0, + }, + Paragraph2: 'For writing permissions,allowing the root user and using insecure ports, you must configure a list of one IP per line, being part of the local network(s).', + Input5: { + Name: 'NFSClientsAllowed', + Type: 'Textarea', + Label: 'NFS Client(s) allowed', + rows : 5 + }, + Input6: { + Name: 'FileSystemPermissions', + Type: 'Selection', + Label: 'File system permissions', + Value: [ + 'Read only', + 'Read and Write', + ], + Default: 0, + }, + Input7: { + Name: 'WriteAsync', + Type: 'Selection', + Label: 'Write (a)synchronously', + Value: [ + 'Synchronous', + 'Asynchronous', + ], + }, + Input8: { + Name: 'DelayWrite', + Type: 'Selection', + Label: 'Delays the disk writing', + Value: [ + 'Write delay', + 'No write delay', + ], + Default: 1, + }, + Input9: { + Name: 'Squash', + Type: 'Selection', + Label: 'Squash the power of users', + Value: [ + 'All users squash', + 'No root squash', + 'root squash', + ], + Default: 2, + }, + Input10: { + Name: 'BrowseParents', + Type: 'Selection', + Label: 'Browse the parent folders', + Value: [ + 'Hide folder', + 'Show folder', + ], + Default: 0, + }, + Input11: { + Name: 'SecurePorts', + Type: 'Selection', + Label: 'Requests on secure ports', + Value: [ + 'Secure', + 'Insecure', + ], + Default: 0, + }, + Paragraph3: 'Set the uid and gid if you want all requests appear to be from one user or one group, otherwise leave blank', + Input12: { + Name: 'SetUID', + Type: 'Textinput', + Label: 'Set the UID.', + }, + Input13: { + Name: 'SetGID', + Type: 'Textinput', + Label: 'Set the GID.', + }, + Submit: 'Save', + }, + { + Name: 'select_ibay', + route:'TABLE', + Header: 'NFS Share Contrib', + SubHeader: 'Manage NFS Ibay settings:', + Nextpanel: 'PARAMS', + Table1: { + Type:'Table', + TableControl:"ibays", + TopHeadings: ['Name','Description','Nfs status', 'Action'], + Columns: ['Name','Description','flag','Modify'] + } + } + ] +} diff --git a/sm1-html-2-json5.py b/sm1-html-2-json5.py new file mode 100644 index 0000000..9200f9f --- /dev/null +++ b/sm1-html-2-json5.py @@ -0,0 +1,261 @@ +import json +import os +import re +from bs4 import BeautifulSoup +from lxml import etree # Import lxml for HTML validation + +def read_html_file(filename): + """Read HTML content from a file.""" + with open(filename, 'r', encoding='utf-8') as file: + return file.read() + +def validate_html(html): + """Validate the HTML content.""" + try: + parser = etree.HTMLParser() + etree.fromstring(html, parser) # Attempt to parse the HTML + except Exception as e: + raise ValueError("Invalid HTML document") from e + +def extract_data(html): + """Extract paragraphs, inputs, tables, and pre blocks from HTML and organize them in order.""" + soup = BeautifulSoup(html, 'lxml') + records = [] + + hidden_input_names = [ + 'page', + 'page_stack', + '.id', + 'csrf_token' + ] + + header_text = None + sub_header_text = None + + # Counter for tables + table_counter = 0 + + # Extract elements while preserving order + for element in soup.find_all(['h1', 'h2', 'p', 'pre', 'input', 'select', 'textarea', 'button', 'table']): + if element.name == 'h1': + header_text = element.get_text(strip=True) + records.append({ + 'Type': 'Header', + 'Text': header_text + }) + + elif element.name == 'h2': + sub_header_text = element.get_text(strip=True) + records.append({ + 'Type': 'SubHeader', + 'Text': sub_header_text + }) + + elif element.name == 'p': + text = element.get_text(strip=True) + if text: # Ignore empty paragraphs + records.append({ + 'Type': 'Paragraph', + 'Text': text + }) + + elif element.name == 'pre': + text = element.get_text(strip=True) + if text: # Ensure non-empty before adding + records.append({ + 'Type': 'Preformatted', + 'Text': text + }) + + elif element.name == 'input': + if element.get('type') == 'hidden' or element.get('name') in hidden_input_names: + continue + + input_info = { + 'Type': element.get('type', 'text').capitalize(), + 'Name': element.get('name'), + 'Value': element.get('value', ''), + } + label = element.find_next('label') + input_info['Label'] = label.get_text(strip=True) if label else None + records.append(input_info) + + elif element.name == 'select': + options = [{'Value': option.get('value'), 'Text': option.get_text(strip=True)} for option in element.find_all('option')] + select_info = { + 'Type': 'Select', + 'Name': element.get('name'), + 'Options': options, + 'Label': element.find_previous('label').get_text(strip=True) if element.find_previous('label') else None, + } + records.append(select_info) + + elif element.name == 'textarea': + textarea_info = { + 'Type': 'Textarea', + 'Name': element.get('name'), + 'Value': element.get_text(strip=True), + } + label = element.find_previous('label') + textarea_info['Label'] = label.get_text(strip=True) if label else None + records.append(textarea_info) + + elif element.name == 'button': + button_info = { + 'Type': 'Button', + 'Name': element.get('name'), + 'Value': element.get_text(strip=True), + 'Label': element.find_previous('label').get_text(strip=True) if label else None, + } + records.append(button_info) + + elif element.name == 'table' and 'sme-border' in element.get('class', []): + # Increment the table counter + table_counter += 1 + + # Prepare the TableControl format + table_control = f"Table{table_counter}" # e.g., "Table1", "Table2" + top_headings = [] + columns = [] + + # Extract headings from the first row + first_row = element.find('tr') + if first_row: + for th in first_row.find_all('th'): + top_headings.append(th.get_text(strip=True)) + + # Extract only the first data row's cell values for Columns + data_rows = element.find_all('tr')[1:] # Skip the heading row + if data_rows: + first_data_row = data_rows[0] # Take the first row of data + for idx, th in enumerate(first_row.find_all('th')): + td = first_data_row.find_all('td')[idx] if idx < len(first_data_row.find_all('td')) else None + if td: + columns.append(f"{table_control}-{th.get_text(strip=True)}") # Format as desired + + records.append({ + 'Type': 'Table', + 'TableControl': table_control, + 'TopHeadings': top_headings, + 'Columns': columns, + }) + + return records, header_text, sub_header_text + +def insert_spaces_before_caps(text): + """Insert spaces before each capital letter in a given string.""" + return re.sub(r'(?