From b3889bb1e31c28d47619e1adb7a9d91b8c7a5132 Mon Sep 17 00:00:00 2001 From: Donald Zou Date: Mon, 8 Sep 2025 15:12:16 +0800 Subject: [PATCH] Feature for #844 --- src/dashboard.py | 34 ++- src/modules/NewConfigurationTemplates.py | 88 ++++++ .../newConfigurationTemplate.vue | 250 ++++++++++++++++++ .../newConfigurationTemplates.vue | 88 ++++++ src/static/app/src/views/newConfiguration.vue | 78 +++--- 5 files changed, 504 insertions(+), 34 deletions(-) create mode 100644 src/modules/NewConfigurationTemplates.py create mode 100644 src/static/app/src/components/newConfigurationComponents/newConfigurationTemplate.vue create mode 100644 src/static/app/src/components/newConfigurationComponents/newConfigurationTemplates.vue diff --git a/src/dashboard.py b/src/dashboard.py index 2d6a00aa..05bd3c4c 100644 --- a/src/dashboard.py +++ b/src/dashboard.py @@ -39,6 +39,7 @@ from logging.config import dictConfig from modules.DashboardClients import DashboardClients from modules.DashboardPlugins import DashboardPlugins from modules.DashboardWebHooks import DashboardWebHooks +from modules.NewConfigurationTemplates import NewConfigurationTemplates dictConfig({ 'version': 1, @@ -214,12 +215,40 @@ def API_SignOut(): session.clear() return resp -@app.route(f'{APP_PREFIX}/api/getWireguardConfigurations', methods=["GET"]) +@app.get(f'{APP_PREFIX}/api/getWireguardConfigurations') def API_getWireguardConfigurations(): InitWireguardConfigurationsList() return ResponseObject(data=[wc for wc in WireguardConfigurations.values()]) -@app.route(f'{APP_PREFIX}/api/addWireguardConfiguration', methods=["POST"]) +@app.get(f'{APP_PREFIX}/api/newConfigurationTemplates') +def API_NewConfigurationTemplates(): + return ResponseObject(data=NewConfigurationTemplates.GetTemplates()) + +@app.get(f'{APP_PREFIX}/api/newConfigurationTemplates/createTemplate') +def API_NewConfigurationTemplates_CreateTemplate(): + return ResponseObject(data=NewConfigurationTemplates.CreateTemplate().model_dump()) + +@app.post(f'{APP_PREFIX}/api/newConfigurationTemplates/updateTemplate') +def API_NewConfigurationTemplates_UpdateTemplate(): + data = request.get_json() + template = data.get('Template', None) + if not template: + return ResponseObject(False, "Please provide template") + + status, msg = NewConfigurationTemplates.UpdateTemplate(template) + return ResponseObject(status, msg) + +@app.post(f'{APP_PREFIX}/api/newConfigurationTemplates/deleteTemplate') +def API_NewConfigurationTemplates_DeleteTemplate(): + data = request.get_json() + template = data.get('Template', None) + if not template: + return ResponseObject(False, "Please provide template") + + status, msg = NewConfigurationTemplates.DeleteTemplate(template) + return ResponseObject(status, msg) + +@app.post(f'{APP_PREFIX}/api/addWireguardConfiguration') def API_addWireguardConfiguration(): data = request.get_json() requiredKeys = [ @@ -1625,6 +1654,7 @@ AllPeerJobs: PeerJobs = PeerJobs(DashboardConfig, WireguardConfigurations) DashboardLogger: DashboardLogger = DashboardLogger() DashboardPlugins: DashboardPlugins = DashboardPlugins(app, WireguardConfigurations) DashboardWebHooks: DashboardWebHooks = DashboardWebHooks(DashboardConfig) +NewConfigurationTemplates: NewConfigurationTemplates = NewConfigurationTemplates() InitWireguardConfigurationsList(startup=True) diff --git a/src/modules/NewConfigurationTemplates.py b/src/modules/NewConfigurationTemplates.py new file mode 100644 index 00000000..9c4511a4 --- /dev/null +++ b/src/modules/NewConfigurationTemplates.py @@ -0,0 +1,88 @@ +import uuid + +from pydantic import BaseModel, field_serializer +import sqlalchemy as db +from .ConnectionString import ConnectionString + + +class NewConfigurationTemplate(BaseModel): + TemplateID: str = '' + Subnet: str = '' + ListenPortStart: int = 0 + ListenPortEnd: int = 0 + Notes: str = "" + +class NewConfigurationTemplates: + def __init__(self): + self.engine = db.create_engine(ConnectionString("wgdashboard")) + self.metadata = db.MetaData() + self.templatesTable = db.Table( + 'NewConfigurationTemplates', self.metadata, + db.Column('TemplateID', db.String(255), primary_key=True), + db.Column('Subnet', db.String(255)), + db.Column('ListenPortStart', db.Integer), + db.Column('ListenPortEnd', db.Integer), + db.Column('Notes', db.Text), + ) + self.metadata.create_all(self.engine) + self.Templates: list[NewConfigurationTemplate] = [] + self.__getTemplates() + + def GetTemplates(self): + self.__getTemplates() + return list(map(lambda x : x.model_dump(), self.Templates)) + + def __getTemplates(self): + with self.engine.connect() as conn: + templates = conn.execute( + self.templatesTable.select() + ).mappings().fetchall() + self.Templates.clear() + self.Templates = [NewConfigurationTemplate(**template) for template in templates] + + def CreateTemplate(self) -> NewConfigurationTemplate: + return NewConfigurationTemplate(TemplateID=str(uuid.uuid4())) + + def SearchTemplate(self, template: NewConfigurationTemplate): + try: + first = next(filter(lambda x : x.TemplateID == template.TemplateID, self.Templates)) + except StopIteration: + return None + return first + + def UpdateTemplate(self, template: dict[str, str]) -> tuple[bool, str] | tuple[bool, None]: + try: + template = NewConfigurationTemplate(**template) + with self.engine.begin() as conn: + if self.SearchTemplate(template): + conn.execute( + self.templatesTable.update().values( + template.model_dump(exclude={'TemplateID'}) + ).where( + self.templatesTable.c.TemplateID == template.TemplateID + ) + ) + else: + conn.execute( + self.templatesTable.insert().values( + template.model_dump() + ) + ) + self.__getTemplates() + except Exception as e: + return False, str(e) + return True, None + + def DeleteTemplate(self, template: dict[str, str]) -> tuple[bool, str] | tuple[bool, None]: + try: + template = NewConfigurationTemplate(**template) + with self.engine.begin() as conn: + conn.execute( + self.templatesTable.delete().where( + self.templatesTable.c.TemplateID == template.TemplateID + ) + ) + self.__getTemplates() + except Exception as e: + return False, str(e) + return True, None \ No newline at end of file diff --git a/src/static/app/src/components/newConfigurationComponents/newConfigurationTemplate.vue b/src/static/app/src/components/newConfigurationComponents/newConfigurationTemplate.vue new file mode 100644 index 00000000..bb5abf95 --- /dev/null +++ b/src/static/app/src/components/newConfigurationComponents/newConfigurationTemplate.vue @@ -0,0 +1,250 @@ + + + + + \ No newline at end of file diff --git a/src/static/app/src/components/newConfigurationComponents/newConfigurationTemplates.vue b/src/static/app/src/components/newConfigurationComponents/newConfigurationTemplates.vue new file mode 100644 index 00000000..3ae4a369 --- /dev/null +++ b/src/static/app/src/components/newConfigurationComponents/newConfigurationTemplates.vue @@ -0,0 +1,88 @@ + + + + + \ No newline at end of file diff --git a/src/static/app/src/views/newConfiguration.vue b/src/static/app/src/views/newConfiguration.vue index adb4c14b..ef101229 100644 --- a/src/static/app/src/views/newConfiguration.vue +++ b/src/static/app/src/views/newConfiguration.vue @@ -1,5 +1,5 @@