From 960f597a7e410d459f6fef1718af35a3d5673b39 Mon Sep 17 00:00:00 2001 From: Amy Parker Date: Mon, 7 Aug 2023 09:39:52 -0700 Subject: [PATCH] the events update This patch adds the events system to SSVP. This is the next major step forward. Signed-off-by: Amy Parker --- Makefile | 5 +- installer/db-setup-mysql.sql | 2 +- installer/db-setup-postgres.sql | 2 +- installer/db-setup-sqlite3.sql | 2 +- js/Makefile | 30 -------- js/common-1.ts | 49 +++++++++++++ js/events-1.ts | 121 ++++++++++++++++++++++++++++++++ js/gen_make_filenames.sh | 25 ------- js/index-1.ts | 30 +------- package-lock.json | 16 +++++ package.json | 1 + scss/custom.scss | 5 +- srv/app.py | 12 +++- srv/dbhandle.py | 59 ++++++++++++++++ web/_header.html | 1 + web/events.html | 16 ++++- web/index.html | 3 +- 17 files changed, 286 insertions(+), 93 deletions(-) delete mode 100644 js/Makefile create mode 100644 js/common-1.ts create mode 100644 js/events-1.ts delete mode 100755 js/gen_make_filenames.sh diff --git a/Makefile b/Makefile index 85e8557..6336ba4 100644 --- a/Makefile +++ b/Makefile @@ -24,13 +24,16 @@ SASS := npx sass SASS_OPTIONS := --trace SASS_SRCS = $(shell find scss/ -name '*.scss') INSTALLDIR := +TSC := npx tsc +TSC_OPTIONS := --noEmitOnError --module es2015 # TODO: automatically compile sass instead of manual all: mkdir -p assets/css assets/js $(SASS) scss/custom.scss:assets/css/custom_bootstrap.css $(SASS_OPTIONS) - $(MAKE) -C js + $(TSC) $(TSC_OPTIONS) --outDir assets/js js/*.ts +# $(MAKE) -C js ssvplwc: cd srv/ssvplwc; cargo run --release diff --git a/installer/db-setup-mysql.sql b/installer/db-setup-mysql.sql index 67ae2f6..b5f4476 100644 --- a/installer/db-setup-mysql.sql +++ b/installer/db-setup-mysql.sql @@ -26,4 +26,4 @@ use ssvp; create table ssvp_day_logs (logDate date not null, serverName text not null, serverStatus integer not null); create table ssvp_interval_logs (logDate datetime not null, serverName text not null, serverStatus boolean not null); create table ssvp_cached_stats (monthlyUptime double not null, yearlyUptime double not null, allTimeUptime double not null, serverName text not null, currentStatus integer not null); -create table ssvp_events (eventID integer not null, serverName text not null, eventName text not null, eventDescription text, startTime datetime not null, endTime datetime, severity integer not null); \ No newline at end of file +create table ssvp_events (eventID integer not null auto_increment, serverName text not null, eventName text not null, eventDescription text, startTime datetime not null, endTime datetime, severity integer not null, primary key (eventID); \ No newline at end of file diff --git a/installer/db-setup-postgres.sql b/installer/db-setup-postgres.sql index eea44dd..5261cd6 100644 --- a/installer/db-setup-postgres.sql +++ b/installer/db-setup-postgres.sql @@ -28,4 +28,4 @@ grant all on all tables in schema public to ssvp; create table ssvp_day_logs (logDate date not null, serverName text not null, serverStatus integer not null); create table ssvp_interval_logs (logDate timestamp not null, serverName text not null, serverStatus boolean not null); create table ssvp_cached_stats (monthlyUptime double precision not null, yearlyUptime double precision not null, allTimeUptime double precision not null, serverName text not null, currentStatus integer not null); -create table ssvp_events (eventID integer not null, serverName text not null, eventName text not null, eventDescription text, startTime timestamp not null, endTime timestamp, severity integer not null); \ No newline at end of file +create table ssvp_events (eventID serial primary key not null, serverName text not null, eventName text not null, eventDescription text, startTime timestamp not null, endTime timestamp, severity integer not null); \ No newline at end of file diff --git a/installer/db-setup-sqlite3.sql b/installer/db-setup-sqlite3.sql index fd8a044..05f5c9d 100644 --- a/installer/db-setup-sqlite3.sql +++ b/installer/db-setup-sqlite3.sql @@ -23,4 +23,4 @@ create table ssvp_day_logs ( logDate date not null, serverName text not null, serverStatus integer not null ); create table ssvp_interval_logs ( logDate datetime not null, serverName text not null, serverStatus boolean not null ); create table ssvp_cached_stats ( monthlyUptime double not null, yearlyUptime double not null, allTimeUptime double not null, serverName text not null, currentStatus integer not null ); -create table ssvp_events ( eventID integer not null, serverName text not null, eventName text not null, eventDescription text, startTime datetime not null, endTime datetime, severity integer not null ); \ No newline at end of file +create table ssvp_events ( eventID integer not null primary key autoincrement, serverName text not null, eventName text not null, eventDescription text, startTime datetime not null, endTime datetime, severity integer not null ); \ No newline at end of file diff --git a/js/Makefile b/js/Makefile deleted file mode 100644 index fa67557..0000000 --- a/js/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -# -# ssvp: server statistics viewer project -# Copyright (C) 2023 Amy Parker -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA or visit the -# GNU Project at https://gnu.org/licenses. The GNU Affero General Public -# License version 3 is available at, for your convenience, -# https://www.gnu.org/licenses/agpl-3.0.en.html. - -TSC := npx tsc -TSC_OPTIONS := --noEmitOnError -TSC_SRCS = $(shell sh gen_make_filenames.sh) - -%.js: %.ts - $(TSC) $(TSC_OPTIONS) --outFile ../assets/js/$@ $< - -all: $(TSC_SRCS) \ No newline at end of file diff --git a/js/common-1.ts b/js/common-1.ts new file mode 100644 index 0000000..b9028b8 --- /dev/null +++ b/js/common-1.ts @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// ssvp: server statistics viewer project +// Copyright (C) 2023 Amy Parker +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA or visit the +// GNU Project at https://gnu.org/licenses. The GNU Affero General Public +// License version 3 is available at, for your convenience, +// https://www.gnu.org/licenses/agpl-3.0.en.html. + +export enum DailyInfo { + Operational = 0, + NonCriticalEvent = 1, + CriticalFailure = 2, + UnknownStatus = -1 +} + +export interface ServerInfo { + monthly_uptime: number; + yearly_uptime: number; + alltime_uptime: number; + current_status: DailyInfo; + daily_types: Array; +} + +export function convertFontColor(ss: DailyInfo): string { + switch (ss) { + case DailyInfo.Operational: + return "text-success"; + case DailyInfo.NonCriticalEvent: + return "text-warning"; + case DailyInfo.CriticalFailure: + return "text-danger"; + default: + return "text-body-tertiary"; + } +} diff --git a/js/events-1.ts b/js/events-1.ts new file mode 100644 index 0000000..87c7544 --- /dev/null +++ b/js/events-1.ts @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// ssvp: server statistics viewer project +// Copyright (C) 2023 Amy Parker +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA or visit the +// GNU Project at https://gnu.org/licenses. The GNU Affero General Public +// License version 3 is available at, for your convenience, +// https://www.gnu.org/licenses/agpl-3.0.en.html. + +import {convertFontColor, DailyInfo} from "./common-1.js"; + +interface EventListing { + eventID: number; + serverName: string; + startTime: Date; + endTime: Date; + severity: DailyInfo; + eventName: string; + eventDescription: string; +} + +const LIM_PER_PAGE: number = 5; + +let eventsList: Array; +let currPage: number = 0; +let numPages: number; +const leftHandler = document.getElementById("pg-bt-left"); +const rightHandler = document.getElementById("pg-bt-right"); + +async function fetchEventsList(page: number) { + if (typeof numPages === "undefined") { + const r = await fetch("/api/v1/size/events"); + numPages = Math.ceil((parseInt(await r.text())) / LIM_PER_PAGE) - 1; + console.log(numPages); + } + if (typeof eventsList === "undefined" || page != currPage) { + currPage = page; + const r = await fetch(`/api/v1/events?lim=${LIM_PER_PAGE}&page=${page}`); + eventsList = await r.json(); + for (let i = 0; i < eventsList.length; ++i) { + eventsList[i].startTime = new Date(eventsList[i].startTime); + if (eventsList[i].endTime != null) + eventsList[i].endTime = new Date(eventsList[i].endTime); + } + if (page != 0) + leftHandler.classList.remove("disabled"); + else + leftHandler.classList.add("disabled"); + if (page < numPages) + rightHandler.classList.remove("disabled"); + else + rightHandler.classList.add("disabled"); + } + generateEventsTable(); +} + +document.getElementById("pg-bt-left") + +fetchEventsList(0); + +function translateDailyInfo(src: DailyInfo): string { + switch (src) { + case DailyInfo.Operational: + return "Informational"; + case DailyInfo.NonCriticalEvent: + return "Non-Critical Event"; + case DailyInfo.CriticalFailure: + return "Critical Event"; + default: + return "Unknown Severity"; + } +} + +function generateEventsTable(): void { + let builder: string = `
+ `; + for (let sp: number = 0; sp < eventsList.length; ++sp) { + const ev: EventListing = eventsList[sp]; + builder += ` + + `; + } + builder += `
+ + + + + +
${ev.eventName}${translateDailyInfo(ev.severity)}
+
+

${ev.eventDescription}

+
+ + + + + +
${ev.serverName} + ${ev.startTime.getUTCFullYear()}/${ev.startTime.getUTCMonth()}/${ev.startTime.getUTCDate()} - + ${ev.endTime == null ? "now" : `${ev.endTime.getUTCFullYear()}/${ev.endTime.getUTCMonth()}/${ev.endTime.getUTCDate()}`} +
+
+
`; + document.getElementById("events-table-gen").innerHTML = builder; +} + +leftHandler.addEventListener("click", () => {fetchEventsList(currPage-1)}); +rightHandler.addEventListener("click", () => {fetchEventsList(currPage+1)}); \ No newline at end of file diff --git a/js/gen_make_filenames.sh b/js/gen_make_filenames.sh deleted file mode 100755 index 966502a..0000000 --- a/js/gen_make_filenames.sh +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -# -# ssvp: server statistics viewer project -# Copyright (C) 2023 Amy Parker -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA or visit the -# GNU Project at https://gnu.org/licenses. The GNU Affero General Public -# License version 3 is available at, for your convenience, -# https://www.gnu.org/licenses/agpl-3.0.en.html. - -for filename in *.ts; do - echo ${filename%.ts}.js -done \ No newline at end of file diff --git a/js/index-1.ts b/js/index-1.ts index d7832ae..2b79f70 100644 --- a/js/index-1.ts +++ b/js/index-1.ts @@ -20,6 +20,8 @@ // License version 3 is available at, for your convenience, // https://www.gnu.org/licenses/agpl-3.0.en.html. +import { DailyInfo, ServerInfo, convertFontColor } from "./common-1.js"; + const EXPANSION_SIZE: number = 1280; const SINGLE_MONTH_SHIFT: number = 800; const DOUBLE_MONTH_SHIFT: number = 1920; @@ -84,13 +86,6 @@ async function serverListInitialization() { serverListInitialization(); -enum DailyInfo { - Operational = 0, - NonCriticalEvent = 1, - CriticalFailure = 2, - UnknownStatus = -1 -} - function dailyinfo_tostring(di: DailyInfo): string { switch (di) { case DailyInfo.Operational: @@ -106,31 +101,10 @@ function dailyinfo_tostring(di: DailyInfo): string { } } -interface ServerInfo { - monthly_uptime: number; - yearly_uptime: number; - alltime_uptime: number; - current_status: DailyInfo; - daily_types: Array; -} - function gen_pct_string(pct: number, sf: number): string { return (Math.round(pct * (10**(sf+2))) / (10**sf)).toString() + "%"; } -function convertFontColor(ss: DailyInfo): string { - switch (ss) { - case DailyInfo.Operational: - return "text-success"; - case DailyInfo.NonCriticalEvent: - return "text-warning"; - case DailyInfo.CriticalFailure: - return "text-danger"; - default: - return "text-body-tertiary"; - } -} - function generate_table(): void { let builder: string = ""; let sp: number = 0; // string pointer diff --git a/package-lock.json b/package-lock.json index e250708..9cdf03d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "dependencies": { "bootstrap": "^5.3.0", + "bootstrap-icons": "^1.10.5", "es6-promise": "^4.2.8", "sass": "^1.64.2", "typescript": "^5.1.6" @@ -68,6 +69,21 @@ "@popperjs/core": "^2.11.7" } }, + "node_modules/bootstrap-icons": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.5.tgz", + "integrity": "sha512-oSX26F37V7QV7NCE53PPEL45d7EGXmBgHG3pDpZvcRaKVzWMqIRL9wcqJUyEha1esFtM3NJzvmxFXDxjJYD0jQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ] + }, "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", diff --git a/package.json b/package.json index ec31fe7..5bb5b90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "dependencies": { "bootstrap": "^5.3.0", + "bootstrap-icons": "^1.10.5", "es6-promise": "^4.2.8", "sass": "^1.64.2", "typescript": "^5.1.6" diff --git a/scss/custom.scss b/scss/custom.scss index 3ae6fd7..ad55948 100644 --- a/scss/custom.scss +++ b/scss/custom.scss @@ -77,6 +77,7 @@ body { border-spacing: 2rem; } -.a-fc-0 { - +#events-table { + border-collapse: separate; + border-spacing: 3rem; } \ No newline at end of file diff --git a/srv/app.py b/srv/app.py index 463d842..cfa154d 100644 --- a/srv/app.py +++ b/srv/app.py @@ -21,7 +21,7 @@ # License version 3 is available at, for your convenience, # https://www.gnu.org/licenses/agpl-3.0.en.html. -from flask import Flask, render_template, send_from_directory, jsonify +from flask import Flask, render_template, send_from_directory, jsonify, request import json import os @@ -83,6 +83,16 @@ def api_v1_ctz_date(): return str(datetime.date.today()) +@app.route("/api/v1/events") +def api_v1_events(): + return jsonify(db.fetch_events(int(request.args.get("lim", 100)), int(request.args.get("page", 0)))) + + +@app.route("/api/v1/size/events") +def api_v1_size_events(): + return jsonify(db.size_events()) + + # If not run using `flask run`, we can pull options from the config file if __name__ == "__main__": app.run(host="::" if config["enable_host_ipv6"] else "0.0.0.0", diff --git a/srv/dbhandle.py b/srv/dbhandle.py index 906e488..4c96141 100644 --- a/srv/dbhandle.py +++ b/srv/dbhandle.py @@ -63,6 +63,14 @@ def update_cached_stats(self, srv: str, st: int) -> None: def init_cs(self, srv: str) -> None: unimplemented() + def fetch_events(self, lim: int, page: int) -> list: + unimplemented() + return [] + + def size_events(self) -> int: + unimplemented() + return 0 + # TODO: create a database of pre-treated SQL on initialization class DBAPIAbstracted(DBAbstract): @@ -94,6 +102,12 @@ def get_uptime_stats(self, srv: str) -> dict: def init_cs(self, srv: str) -> None: return self._ics(srv=srv, conn=self._generate_connection()) + def fetch_events(self, lim: int, page: int) -> list: + return self._fev(lim=lim, page=page, conn=self._generate_connection()) + + def size_events(self) -> int: + return self._sev(conn=self._generate_connection()) + def _ups(self, srv: str, conn) -> dict: curr = conn.cursor() sql = f"select monthlyUptime, yearlyUptime, allTimeUptime, currentStatus \ @@ -232,3 +246,48 @@ def _ics(self, srv: str, conn) -> None: conn.commit() curr.close() conn.close() + + def _fev(self, lim: int, page: int, conn) -> list: + curr = conn.cursor() + sql = f"select eventID, serverName, startTime, endTime, severity, eventName, eventDescription \ + from {self.p}events \ + order by \ + (case \ + when endTime is null \ + then 1 \ + else \ + 0 \ + end) desc, \ + startTime desc \ + limit %s,%s;" + curr.execute(self._treat_sql(sql), (lim*page, lim)) + res = [] + try: + res = [{ + "eventID": x[0], + "serverName": x[1], + "startTime": x[2], + "endTime": x[3], + "severity": x[4], + "eventName": x[5], + "eventDescription": x[6] + } for x in curr.fetchall()] + except psycopg2.ProgrammingError: + pass + curr.close() + conn.close() + return res + + def _sev(self, conn) -> int: + curr = conn.cursor() + sql = f"select count(eventID) \ + from {self.p}events;" + curr.execute(self._treat_sql(sql)) + res = 0 + try: + res = curr.fetchone()[0] + except psycopg2.ProgrammingError: + pass + curr.close() + conn.close() + return res diff --git a/web/_header.html b/web/_header.html index 4a8c552..854fdcb 100644 --- a/web/_header.html +++ b/web/_header.html @@ -5,6 +5,7 @@ {{ config["instance_name"] }} + diff --git a/web/events.html b/web/events.html index ca33eb0..bbc2173 100644 --- a/web/events.html +++ b/web/events.html @@ -1,6 +1,18 @@ {% include "_header.html" %}
-

Event Log

-

Not yet implemented...

+
+
+ + + + + +

Event Log

+ +
+ + + + {% include "_footer.html" %} \ No newline at end of file diff --git a/web/index.html b/web/index.html index 6d69b8b..e6abad2 100644 --- a/web/index.html +++ b/web/index.html @@ -6,5 +6,6 @@
- + + {% include "_footer.html" %} \ No newline at end of file