diff --git a/.gitignore b/.gitignore index 0367ab9..ef6166a 100644 --- a/.gitignore +++ b/.gitignore @@ -271,3 +271,5 @@ pyrightconfig.json *.xhtml # End of https://www.toptal.com/developers/gitignore/api/python,flask,web + +tmp.py \ No newline at end of file diff --git a/app.py b/app.py index ba04bdc..486f1d3 100644 --- a/app.py +++ b/app.py @@ -21,16 +21,26 @@ def urlOfService(services, service): return services[service]["url"] return "NaN" -def updateStatusService(services, service): +def updateStatusService(services, service, session=None): url = urlOfService(services, service) if url == "NaN": print("[LOG]: You passed a service that is not tracked") return False print(f"[LOG]: HTTP request for {services[service]["url"]}") - response = requests.get(url).status_code < 400 # Starting 400 codes are error for HTTP GET + headers = {"User-Agent": "Mozilla/5.0 (X11; CrOS x86_64 12871.102.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.141 Safari/537.36"} + if session is not None: + # This line is sooooo slow + response = session.head(url, headers=headers).status_code < 400 # Using a session to speed up refresh in a batch + else: + # This line is sooooo slow + response = requests.head(url, headers=headers).status_code < 400 # Starting 400 codes are error for HTTP GET + + + print("[LOG]: got status ") jsonUtility.updateStatus(services, service, response) + dataReport.reportStatus(services, service) return response @@ -44,8 +54,10 @@ def statusService(services, service): def refreshServices(services): print("[LOG]: Refreshing the services") + session = requests.Session() + for service in services.keys(): - updateStatusService(services, service) + updateStatusService(services, service, session) # Setup Scheduler to periodically check the status of the website scheduler = BackgroundScheduler() @@ -133,9 +145,17 @@ def page_not_found(error): @app.route("/extract") def extractLog(): get_what_to_extract = request.args.get("get") + print(get_what_to_extract.split("_")) - if get_what_to_extract in services.keys() or get_what_to_extract == "request": - with open("data/" + get_what_to_extract + "/log.csv", "r") as file: + if get_what_to_extract.split("_")[0] in services.keys() or get_what_to_extract == "request": + print("in keys") + if len(get_what_to_extract.split("_")) > 1: + # when we want to extract the past outages not the user outages + path = "data/" + get_what_to_extract.split("_")[0] + "/outageReport.csv" + else: + path = "data/" + get_what_to_extract + "/log.csv" + + with open(path, "r") as file: csv_data = list(csv.reader(file, delimiter=",")) response = make_response() @@ -147,7 +167,7 @@ def extractLog(): return response else: - return 404 + return render_template("404.html") @app.route('/robots.txt') @app.route('/sitemap.xml') diff --git a/data/404-Test/log.csv b/data/404-Test/log.csv index 828ef5f..374830d 100644 --- a/data/404-Test/log.csv +++ b/data/404-Test/log.csv @@ -7,3 +7,4 @@ date,UP 2024-01-22T22:28:36,False 2024-01-23T09:55:10,False 2024-01-23T12:15:12,False +2024-01-23T20:44:12,False diff --git a/data/404-Test/outageReport.csv b/data/404-Test/outageReport.csv new file mode 100644 index 0000000..1852435 --- /dev/null +++ b/data/404-Test/outageReport.csv @@ -0,0 +1,13 @@ +date,UP +2024-01-24T07:38:21,False +2024-01-24T07:39:17,False +2024-01-24T07:41:35,False +2024-01-24T07:42:45,False +2024-01-24T07:43:26,False +2024-01-24T07:45:07,False +2024-01-24T07:51:12,False +2024-01-24T07:56:47,False +2024-01-24T07:59:04,False +2024-01-24T08:00:38,False +2024-01-24T08:06:13,False +2024-01-24T08:07:51,False diff --git a/data/ADE-Scheduler/outageReport.csv b/data/ADE-Scheduler/outageReport.csv new file mode 100644 index 0000000..0bd0f1c --- /dev/null +++ b/data/ADE-Scheduler/outageReport.csv @@ -0,0 +1,10 @@ +date,UP +2024-01-24T07:39:40,True +2024-01-24T07:41:58,True +2024-01-24T07:43:48,True +2024-01-24T07:45:30,True +2024-01-24T07:51:34,True +2024-01-24T07:57:10,True +2024-01-24T07:59:27,True +2024-01-24T08:01:00,True +2024-01-24T08:06:36,True diff --git a/data/ADE/outageReport.csv b/data/ADE/outageReport.csv new file mode 100644 index 0000000..14e0f95 --- /dev/null +++ b/data/ADE/outageReport.csv @@ -0,0 +1,10 @@ +date,UP +2024-01-24T07:39:39,True +2024-01-24T07:41:57,True +2024-01-24T07:43:48,True +2024-01-24T07:45:29,True +2024-01-24T07:51:34,True +2024-01-24T07:57:10,True +2024-01-24T07:59:26,True +2024-01-24T08:01:00,True +2024-01-24T08:06:35,True diff --git a/data/Comproved/outageReport.csv b/data/Comproved/outageReport.csv new file mode 100644 index 0000000..a2b294f --- /dev/null +++ b/data/Comproved/outageReport.csv @@ -0,0 +1,8 @@ +date,UP +2024-01-24T07:40:23,True +2024-01-24T07:44:31,True +2024-01-24T07:46:13,True +2024-01-24T07:52:17,True +2024-01-24T07:57:53,True +2024-01-24T08:01:43,True +2024-01-24T08:07:19,True diff --git a/data/Gradescope/outageReport.csv b/data/Gradescope/outageReport.csv new file mode 100644 index 0000000..23da023 --- /dev/null +++ b/data/Gradescope/outageReport.csv @@ -0,0 +1,8 @@ +date,UP +2024-01-24T07:40:25,True +2024-01-24T07:44:33,True +2024-01-24T07:46:14,True +2024-01-24T07:52:19,True +2024-01-24T07:57:55,True +2024-01-24T08:01:45,True +2024-01-24T08:07:20,True diff --git a/data/Intranet/outageReport.csv b/data/Intranet/outageReport.csv new file mode 100644 index 0000000..cbf7d5e --- /dev/null +++ b/data/Intranet/outageReport.csv @@ -0,0 +1,7 @@ +date,UP +2024-01-24T07:40:47,True +2024-01-24T07:46:15,True +2024-01-24T07:52:19,True +2024-01-24T07:57:56,True +2024-01-24T08:01:45,True +2024-01-24T08:07:21,True diff --git a/data/LEPL1104/outageReport.csv b/data/LEPL1104/outageReport.csv new file mode 100644 index 0000000..0e94c25 --- /dev/null +++ b/data/LEPL1104/outageReport.csv @@ -0,0 +1,7 @@ +date,UP +2024-01-24T07:40:48,True +2024-01-24T07:46:15,True +2024-01-24T07:52:20,True +2024-01-24T07:57:56,True +2024-01-24T08:01:46,True +2024-01-24T08:07:22,True diff --git a/data/LEPL1201/outageReport.csv b/data/LEPL1201/outageReport.csv new file mode 100644 index 0000000..4700076 --- /dev/null +++ b/data/LEPL1201/outageReport.csv @@ -0,0 +1,7 @@ +date,UP +2024-01-24T07:40:49,True +2024-01-24T07:46:16,True +2024-01-24T07:52:20,True +2024-01-24T07:57:57,True +2024-01-24T08:01:46,True +2024-01-24T08:07:22,True diff --git a/data/Moodle/outageReport.csv b/data/Moodle/outageReport.csv new file mode 100644 index 0000000..081b8b9 --- /dev/null +++ b/data/Moodle/outageReport.csv @@ -0,0 +1,5 @@ +date,UP +2024-01-24T07:46:25,True +2024-01-24T07:52:43,True +2024-01-24T07:58:19,True +2024-01-24T08:02:09,True diff --git a/data/UCLouvain/outageReport.csv b/data/UCLouvain/outageReport.csv new file mode 100644 index 0000000..d714e63 --- /dev/null +++ b/data/UCLouvain/outageReport.csv @@ -0,0 +1,5 @@ +date,UP +2024-01-24T07:46:26,True +2024-01-24T07:52:43,True +2024-01-24T07:58:20,True +2024-01-24T08:02:09,True diff --git a/dataReport.py b/dataReport.py index c3f9200..ded7117 100644 --- a/dataReport.py +++ b/dataReport.py @@ -31,53 +31,66 @@ def addBlankCSV(): log.write(cols) -def plot(service): - path = filepath + service + "/log.csv" - size = os.path.getsize(path) +def plot(service, onlyOutageReport=False): + if not onlyOutageReport: + print("[LOG]: also plotting for user Report") + toPlot = dict(userReport = filepath + service + "/outageReport.csv") + else: + toPlot = dict(outageReport = filepath + service + "/outageReport.csv") - fig,ax = plt.subplots() - if len(cols) + 5 >= size: - # It means we have just created the skeleton of the logs and there is no current logs - text_kwargs = dict(ha='center', va='center', fontsize=28) + for report in toPlot: + path = toPlot[report] - fig.text(0.5, 0.5, 'No Data at The moment', **text_kwargs) - else: - # Great there is some data ! - # Define a custom converter for the date column - date_converter = lambda x: np.datetime64(x.decode("utf-8")) + size = os.path.getsize(path) + + fig,ax = plt.subplots() - # Specify the data types and converters for each column - dtypes = np.dtype([("date", "datetime64[s]"), ("UP", "bool")]) - converters = {"date": date_converter} + if len(cols) + 5 >= size: + # It means we have just created the skeleton of the logs and there is no current logs + text_kwargs = dict(ha='center', va='center', fontsize=28) + + fig.text(0.5, 0.5, 'No Data at The moment', **text_kwargs) + else: + # Great there is some data ! + # Define a custom converter for the date column + date_converter = lambda x: np.datetime64(x.decode("utf-8")) + + # Specify the data types and converters for each column + dtypes = np.dtype([("date", "datetime64[s]"), ("UP", "bool")]) + converters = {"date": date_converter} - # Load the CSV file into a NumPy array - data = np.genfromtxt(path, delimiter=",", names=True, dtype=dtypes, converters=converters) + # Load the CSV file into a NumPy array + data = np.genfromtxt(path, delimiter=",", names=True, dtype=dtypes, converters=converters) - # Print the loaded data - timeArray = data["date"] - UPArray = data["UP"] - - timeNow = np.datetime64("now") - - ax.plot(timeArray, UPArray, marker = "o") - ax.axvline(x=timeNow, linestyle="--", color="gray", alpha=0.5) - - now_kwargs = dict(color="red",ha='left', va='bottom') - - # To protect against unwanted behavior - if timeArray.size > 2: - ax.set_xlim(timeArray[0] - np.timedelta64(3, "m"), timeNow + np.timedelta64(3, "m")) - ax.text(timeNow - np.timedelta64((timeNow - timeArray[0]))*0.34 , 0.5, f"Last Report\n{timeNow}", **now_kwargs) + # Print the loaded data + timeArray = data["date"] + UPArray = data["UP"] + + timeNow = np.datetime64("now") + + ax.plot(timeArray, UPArray, marker = "o") + ax.axvline(x=timeNow, linestyle="--", color="gray", alpha=0.5) + + now_kwargs = dict(color="red",ha='left', va='bottom') + + # To protect against unwanted behavior + if timeArray.size > 2: + ax.set_xlim(timeArray[0] - np.timedelta64(3, "m"), timeNow + np.timedelta64(3, "m")) + ax.text(timeNow - np.timedelta64((timeNow - timeArray[0]))*0.34 , 0.5, f"Last Report\n{timeNow}", **now_kwargs) + else: + ax.text(timeNow, 0.5, f"Last Report\n{timeNow}", **now_kwargs) + + if report == "userReport": + ax.set_title(f"Status reported by users for {service}") + else: + ax.set_title(f"Past status for {service}") + ax.set_ylabel("Up or Down") + ax.set_xlabel("Date and Time") + if not onlyOutageReport: + toPlot = dict(userReport = filepath + service + "/outageReport.csv") else: - ax.text(timeNow, 0.5, f"Last Report\n{timeNow}", **now_kwargs) - - - ax.set_title(f"Status reported by users for {service}") - ax.set_ylabel("Up or Down") - ax.set_xlabel("Date and Time") - - fig.savefig("static/img/log/" + service + ".png") + fig.savefig("static/img/log/" + report + service + ".png") def addReport(service, user_choice): """Function to add a new line to the logs of each service @@ -130,6 +143,46 @@ def newRequest(serviceName, url, info): with open(log, "a") as file: file.write(date + "," + serviceName + "," + url + "," + info + "\n") +def blankStatus(): + for service in serviceList: + try: + os.mkdir(filepath + service) + + except FileExistsError: + pass + except: + raise ValueError(f"[LOG]: Something went wrong with creating the folder {service}") + + for service in serviceList: + with open(filepath + service + "/outageReport.csv", "w") as log: + log.write(cols) + +def reportStatus(services, service): + """Add the log of the current status of the site so we can track it throughout time + + Args: + services (dict): the loaded services.json + service (string): the specific service we want to report + """ + + print("[LOG]: starting Report") + date = services[service]["Last access time"] + UP = services[service]["Last status"] + + path = filepath + service + "/outageReport.csv" + + with open(path, "a") as out: + out.write(date + "," + str(UP) + "\n") + + print("[LOG]: Finished Report") + print("[LOG]: starting plot") + + + plot(service, True) + print("[LOG]: Finished plot") + + + if __name__ == "__main__": dataExtraction() \ No newline at end of file diff --git a/services.json b/services.json index d1e4f04..607fa64 100644 --- a/services.json +++ b/services.json @@ -1,51 +1,51 @@ { "404-Test": { - "Last access time": "2024-01-23T20:41:43", + "Last access time": "2024-01-24T08:07:51", "Last status": false, "url": "https://www.google.com/404" }, "ADE": { - "Last access time": "2024-01-23T20:41:43", + "Last access time": "2024-01-24T08:06:35", "Last status": true, "url": "https://horaire.uclouvain.be/direct/" }, "ADE-Scheduler": { - "Last access time": "2024-01-23T20:41:44", + "Last access time": "2024-01-24T08:06:36", "Last status": true, "url": "https://ade-scheduler.info.ucl.ac.be/calendar/" }, "Comproved": { - "Last access time": "2024-01-23T20:41:45", + "Last access time": "2024-01-24T08:07:19", "Last status": true, "url": "https://app.comproved.com/universite-de-louvain" }, "Gradescope": { - "Last access time": "2024-01-23T20:41:46", + "Last access time": "2024-01-24T08:07:20", "Last status": true, "url": "https://www.gradescope.com/" }, "Intranet": { - "Last access time": "2024-01-23T20:41:47", + "Last access time": "2024-01-24T08:07:21", "Last status": true, "url": "https://intranet.uclouvain.be" }, "LEPL1104": { - "Last access time": "2024-01-23T20:41:48", + "Last access time": "2024-01-24T08:07:22", "Last status": true, "url": "https://perso.uclouvain.be/vincent.legat/zouLab/epl1104.php" }, "LEPL1201": { - "Last access time": "2024-01-23T20:41:24", + "Last access time": "2024-01-24T08:07:22", "Last status": true, "url": "https://perso.uclouvain.be/vincent.legat/zouLab/epl1201.php" }, "Moodle": { - "Last access time": "2024-01-23T20:41:25", + "Last access time": "2024-01-24T08:02:09", "Last status": true, "url": "https://moodle.uclouvain.be/" }, "UCLouvain": { - "Last access time": "2024-01-23T20:41:27", + "Last access time": "2024-01-24T08:02:09", "Last status": true, "url": "https://www.uclouvain.be/" } diff --git a/static/img/log/outageReport.png b/static/img/log/outageReport.png new file mode 100644 index 0000000..983a25b Binary files /dev/null and b/static/img/log/outageReport.png differ diff --git a/static/img/log/outageReport404-Test.png b/static/img/log/outageReport404-Test.png new file mode 100644 index 0000000..6ee14c5 Binary files /dev/null and b/static/img/log/outageReport404-Test.png differ diff --git a/static/img/log/outageReportADE-Scheduler.png b/static/img/log/outageReportADE-Scheduler.png new file mode 100644 index 0000000..601dfe9 Binary files /dev/null and b/static/img/log/outageReportADE-Scheduler.png differ diff --git a/static/img/log/outageReportADE.png b/static/img/log/outageReportADE.png new file mode 100644 index 0000000..394ad76 Binary files /dev/null and b/static/img/log/outageReportADE.png differ diff --git a/static/img/log/outageReportComproved.png b/static/img/log/outageReportComproved.png new file mode 100644 index 0000000..180b79a Binary files /dev/null and b/static/img/log/outageReportComproved.png differ diff --git a/static/img/log/outageReportGradescope.png b/static/img/log/outageReportGradescope.png new file mode 100644 index 0000000..542d072 Binary files /dev/null and b/static/img/log/outageReportGradescope.png differ diff --git a/static/img/log/outageReportIntranet.png b/static/img/log/outageReportIntranet.png new file mode 100644 index 0000000..e70d7cb Binary files /dev/null and b/static/img/log/outageReportIntranet.png differ diff --git a/static/img/log/outageReportLEPL1104.png b/static/img/log/outageReportLEPL1104.png new file mode 100644 index 0000000..4fdaa0f Binary files /dev/null and b/static/img/log/outageReportLEPL1104.png differ diff --git a/static/img/log/outageReportLEPL1201.png b/static/img/log/outageReportLEPL1201.png new file mode 100644 index 0000000..ecc40cf Binary files /dev/null and b/static/img/log/outageReportLEPL1201.png differ diff --git a/static/img/log/outageReportMoodle.png b/static/img/log/outageReportMoodle.png new file mode 100644 index 0000000..d6d3169 Binary files /dev/null and b/static/img/log/outageReportMoodle.png differ diff --git a/static/img/log/outageReportUCLouvain.png b/static/img/log/outageReportUCLouvain.png new file mode 100644 index 0000000..d6ae2e5 Binary files /dev/null and b/static/img/log/outageReportUCLouvain.png differ diff --git a/static/styleItem.css b/static/styleItem.css index 1354506..dcec19e 100644 --- a/static/styleItem.css +++ b/static/styleItem.css @@ -48,6 +48,25 @@ h2{ border: 20px; } +.container-plot { + max-width: 100%; /* Set your desired maximum width */ + min-width: 100px; /* Set your desired minimum width */ + text-align: center; /* Center the content horizontally */ + + color: white; + + border: 20px; + display: flex; + + align-items: center; /* Center vertically */ + justify-content: center; /* Center horizontally */ +} + +#graph-container{ + flex:1; + margin-right: 10px; +} + #up { display: inline-block; /* Ensure the link behaves like a block-level element */ padding: 10px 150px 10px 150px; /* Optional: Add padding for better visual appearance */ @@ -156,7 +175,7 @@ button.no:hover{ height: 20px; } -#graph{ +.graph{ flex:1; max-width: 600px; diff --git a/templates/itemWebsite.html b/templates/itemWebsite.html index 0794ac0..17271d9 100644 --- a/templates/itemWebsite.html +++ b/templates/itemWebsite.html @@ -35,14 +35,22 @@

Is this website currently working for you ?

-
-
- Graph for {{ service }} +
+
+ Graph for status reported by user for {{ service }} +
+ Download Log   -   + Download Graph +
+
+ Graph of previous status for {{ service }} +
+ Download Log   -   + Download Graph
- Download Log   -   - Download Graph + {% endblock %}