From f6e625c5f88c551de11f3fb4d1d85944eaceecaf Mon Sep 17 00:00:00 2001 From: Donald Zou Date: Fri, 22 Aug 2025 18:26:31 +0800 Subject: [PATCH] Webhook UI --- src/dashboard.py | 19 ++ src/modules/DashboardWebHooks.py | 40 +++- src/static/app/src/App.vue | 5 +- .../accountSettingsInputPassword.vue | 111 ++++----- .../settingsComponent/dashboardAPIKeys.vue | 1 + .../dashboardEmailSettings.vue | 1 + .../settingsComponent/dashboardWebHooks.vue | 89 +++++++ .../addWebHook.vue | 225 ++++++++++++++++++ .../settingsComponent/wgdashboardSettings.vue | 25 +- 9 files changed, 438 insertions(+), 78 deletions(-) create mode 100644 src/static/app/src/components/settingsComponent/dashboardWebHooksComponents/addWebHook.vue diff --git a/src/dashboard.py b/src/dashboard.py index fe49e508..c72e1807 100644 --- a/src/dashboard.py +++ b/src/dashboard.py @@ -66,6 +66,8 @@ class CustomJsonEncoder(DefaultJSONProvider): return o.toJson() if type(o) is RowMapping: return dict(o) + if type(o) is datetime: + return o.strftime("%Y-%m-%d %H:%M:%S") return super().default(self) app.json = CustomJsonEncoder(app) @@ -1368,6 +1370,23 @@ def API_Clients_DeleteClient(): if not DashboardClients.GetClient(clientId): return ResponseObject(False, "Client does not exist") return ResponseObject(status=DashboardClients.DeleteClient(clientId)) + +@app.get(f'{APP_PREFIX}/api/webHooks/getWebHooks') +def API_WebHooks_GetWebHooks(): + return ResponseObject(data=DashboardWebHooks.GetWebHooks()) + +@app.get(f'{APP_PREFIX}/api/webHooks/createWebHook') +def API_WebHooks_createWebHook(): + return ResponseObject(data=DashboardWebHooks.CreateWebHook().model_dump( + exclude={'CreationDate'} + )) + +@app.post(f'{APP_PREFIX}/api/webHooks/updateWebHook') +def API_WebHooks_UpdateWebHook(): + data = request.get_json() + status, msg = DashboardWebHooks.UpdateWebHook(data) + return ResponseObject(status, msg) + ''' Index Page ''' diff --git a/src/modules/DashboardWebHooks.py b/src/modules/DashboardWebHooks.py index d736fe6b..06e53a87 100644 --- a/src/modules/DashboardWebHooks.py +++ b/src/modules/DashboardWebHooks.py @@ -7,14 +7,14 @@ from .ConnectionString import ConnectionString WebHookActions = ['peer_created', 'peer_deleted', 'peer_updated'] class WebHook(BaseModel): - WebHookID: str = uuid.uuid4() + WebHookID: str = '' PayloadURL: str = '' - ContentType: str = '' - Headers: dict[str, str] = {} + ContentType: str = 'application/json' + Headers: dict[str, dict[str, str]] = {} VerifySSL: bool = True SubscribedActions: list[str] = WebHookActions IsActive: bool = True - CreationDate: datetime = datetime.now() + CreationDate: datetime = '' Notes: str = '' class DashboardWebHooks: @@ -26,11 +26,14 @@ class DashboardWebHooks: db.Column('WebHookID', db.String(255), nullable=False, primary_key=True), db.Column('PayloadURL', db.Text, nullable=False), db.Column('ContentType', db.String(255), nullable=False), - db.Column('Headers', db.Text), + db.Column('Headers', db.JSON), db.Column('VerifySSL', db.Boolean, nullable=False), - db.Column('SubscribedActions', db.Text), + db.Column('SubscribedActions', db.JSON), db.Column('IsActive', db.Boolean, nullable=False), - db.Column('CreationDate', (db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP), nullable=False), + db.Column('CreationDate', + (db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP), + server_default=db.func.now(), + nullable=False), db.Column('Notes', db.Text), extend_existing=True ) @@ -41,13 +44,19 @@ class DashboardWebHooks: def __getWebHooks(self): with self.engine.connect() as conn: webhooks = conn.execute( - self.webHooksTable.select() + self.webHooksTable.select().order_by( + self.webHooksTable.c.CreationDate + ) ).mappings().fetchall() self.WebHooks.clear() self.WebHooks = [WebHook(**webhook) for webhook in webhooks] + + def GetWebHooks(self): + self.__getWebHooks() + return list(map(lambda x : x.model_dump(), self.WebHooks)) - def CreateWebHook(self): - return WebHook().model_dump() + def CreateWebHook(self) -> WebHook: + return WebHook(WebHookID=str(uuid.uuid4())) def SearchWebHook(self, webHook: WebHook) -> WebHook | None: try: @@ -58,7 +67,15 @@ class DashboardWebHooks: def UpdateWebHook(self, webHook: dict[str, str]) -> tuple[bool, str] | tuple[bool, None]: try: - webHook = WebHook.model_validate(webHook) + webHook = WebHook(**webHook) + + if len(webHook.PayloadURL) == 0: + return False, "Payload URL cannot be empty" + + if len(webHook.ContentType) == 0 or webHook.ContentType not in ['application/json', 'application/x-www-form-urlencoded']: + return False, "Content Type is invalid" + + with self.engine.begin() as conn: if self.SearchWebHook(webHook): conn.execute( @@ -69,6 +86,7 @@ class DashboardWebHooks: ) ) else: + webHook.CreationDate = datetime.now() conn.execute( self.webHooksTable.insert().values( webHook.model_dump() diff --git a/src/static/app/src/App.vue b/src/static/app/src/App.vue index 181aa11a..13711b0f 100644 --- a/src/static/app/src/App.vue +++ b/src/static/app/src/App.vue @@ -22,7 +22,7 @@ fetchGet("/api/locale", {}, (res) => {