From fd034d0cae527d8b070b40284db18a5cb7d91c4b Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Sun, 9 Apr 2023 17:52:30 +0200 Subject: [PATCH 01/13] Add new frame with navigation buttons and icon --- assets/browse_reports_dark.png | Bin 0 -> 765 bytes assets/browse_reports_light.png | Bin 0 -> 640 bytes frames/AnydeskFrame.py | 14 ++++++-------- frames/BrowseReportsFrame.py | 10 ++++++++++ main.py | 27 +++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 assets/browse_reports_dark.png create mode 100644 assets/browse_reports_light.png create mode 100644 frames/BrowseReportsFrame.py diff --git a/assets/browse_reports_dark.png b/assets/browse_reports_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..f04b153e52c15629acd17d064730d64e53f337d0 GIT binary patch literal 765 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sZv%WnT!Hle5d(5~Ci(+C>{k-x z7tFxO%)-Xb!7C^tDkd%^Eh8(Zq^7N7ZeeL<6BHU285NzFUr<<7TvA%z(A?6|+11_C z+c#;-jG5~;Z`rzS`~Cw5kKKRx`02Cf-+%o6^Y@=l&0l?>$&5+f?k;|kiG}xp>=aKI z#}JR>cdy+HI%FWi_F(@5y-T~Ax+1nOdc>qBqM`6^>ZSjG<&Ss!Ex%#rS^ce}rMPK}>VZ410@V)9dwP#We@s1o=~hqkHl`a5p5N+yUMldOiDxfld0}_A$RcOQ z7q3-Y`c62`xTbhB^quojWp*nD3Fk}q!{m9pm%QHcUS_&Vu5T=VSji6|rM(ShZYrMZ zcc&hA{p9uM7CXb=4{HLo8E5%!TI{KR^yS$@XQUr5x>4glY5U}-k{1=@!#+>h`|ZcB jiSL~kuKjb)|Co70#WK^A(*M5!1E0au)z4*}Q$iB}E!@)F literal 0 HcmV?d00001 diff --git a/assets/browse_reports_light.png b/assets/browse_reports_light.png new file mode 100644 index 0000000000000000000000000000000000000000..253baddbd4c040bc610b712e60c1da1fb154ba40 GIT binary patch literal 640 zcmV-`0)PF9P)Px%I!Q!9RA@u(nTt&WF${*?Nq|jY63QgNB)}xlNq|W}KRP4VO>E!gaXINCp-R+E z{P~&3fi^x48`qz9fVDm7dEk+Vjzn}_Nzo@Fdag9r-!v8g6o09?*fdvF2n*nyh;ADI zV9II`7Ql~C-U~I46QKyD<){L&CO{QWtPM~MF#>uK`UEgatpu7BnBL+ z)qV8jHd+$Tc47&D3^8xvJ0ki}LfjW%?QbIbO2~NgnrC7!2ciI4c__}81t|pqg5TiN z9j!f}kB!lb0x16)$%7IA*E&idr93OjTMd1Q@Gya7*XjiT1wVxrxiEnou5uW}4X0iJ zvc4mk5#za`Ax!yR05aiI6-mQrk7f1j0f2DeZL(*52_n6gg)RX=Da?(NsOd6!QCX0f zks&X`vX@{b09GH63x*U)5FwcXkCClLtpKE@mxd6k7I*9JA%v{~ATVS?qAbFidRyTo z@lCEXmv|r&$1Ecg5)e?x8dBcOn_d7*8yO(8*2kB<0I-(cO28BH54nhn=2xc&5vQU$1Wf&fau;m z>WQUKN+yH_01Lr7IP%qc>|<{rL_#O7$vP6^tPF>)E}|xGEXT*tvmUY~fTVqPfW~3t aPX7yn2Ba}Ha7q#Y0000 Date: Sun, 9 Apr 2023 21:08:50 +0200 Subject: [PATCH 02/13] Add list of buttons with reports --- frames/BrowseReportsFrame.py | 66 +++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/frames/BrowseReportsFrame.py b/frames/BrowseReportsFrame.py index de2b025..c723484 100644 --- a/frames/BrowseReportsFrame.py +++ b/frames/BrowseReportsFrame.py @@ -1,10 +1,74 @@ +import os import customtkinter +from typing import Literal + + +def get_reports_folder_list(): + try: + return os.listdir(os.path.join(os.getcwd(), "reports")) + except FileNotFoundError: + os.mkdir(os.path.join(os.getcwd(), "reports")) + return os.listdir(os.path.join(os.getcwd(), "reports")) + + +def refresh(navigation_panel): + for widget in navigation_panel.winfo_children(): + widget.destroy() + d = {} + for report in get_reports_folder_list(): + d[report] = Report_Button(navigation_panel, report_name=report, + report_path=os.path.join(os.getcwd(), "reports", report)) + + navigation_panel.label = customtkinter.CTkLabel(navigation_panel, text="Reports List", + text_color=("#333", "#ccc"), + font=customtkinter.CTkFont(size=15, weight="bold")) + navigation_panel.label.grid(row=0, column=0, padx=20) + add_widgets(d, rowstart=1, columnstart=0, orientation="vertical") + + +class Report_Button(customtkinter.CTkButton): + def __init__(self, master, **kwargs): + super().__init__(master) + + self.report_name = kwargs.get("report_name") + self.report_path = kwargs.get("report_path") + + self.configure(text=self.report_name, command=self.open_report) + + def open_report(self): + os.startfile(self.report_path) + + +def add_widgets(d, rowstart: int = 0, columnstart: int = 0, orientation: Literal["vertical", "horizontal"] = +"vertical"): + for i, (key, value) in enumerate(d.items()): + if orientation == "vertical": + value.grid(row=rowstart + i, column=columnstart, sticky="ew", padx=20, pady=10) + elif orientation == "horizontal": + value.grid(row=rowstart + i, column=columnstart + i, sticky="ew", padx=20, pady=10) + + +class Navigation_Panel(customtkinter.CTkScrollableFrame): + + def __init__(self, master, **kwargs): + super().__init__(master, **kwargs) + + self.grid(row=0, column=0, sticky="nsew") + self.grid_columnconfigure(0, weight=1) + # add widgets onto the frame... + refresh(self) class BrowseReportsFrame(customtkinter.CTkFrame): - """Home frame class.""" + """Browse Reports frame class.""" def __init__(self, master, **kwargs): super().__init__(master, **kwargs) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) + + self.navigation_panel = Navigation_Panel(self) + + self.refresh_button = customtkinter.CTkButton(self, text="Refresh", + command=lambda: refresh(self.navigation_panel)) + self.refresh_button.grid(row=1, column=0, sticky="ew", padx=20, pady=10) From fe5ddd9a04225b616cf00e1aaae5a9e94790c19b Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Sun, 9 Apr 2023 22:56:27 +0200 Subject: [PATCH 03/13] Create report frames that contain labels and buttons --- frames/BrowseReportsFrame.py | 75 ++++++++++++++++++++++++++++-------- main.py | 3 +- utils/file_operations.py | 9 +++++ 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/frames/BrowseReportsFrame.py b/frames/BrowseReportsFrame.py index c723484..7afaca0 100644 --- a/frames/BrowseReportsFrame.py +++ b/frames/BrowseReportsFrame.py @@ -1,6 +1,8 @@ import os import customtkinter from typing import Literal +import csv +from utils.file_operations import split_filename def get_reports_folder_list(): @@ -11,21 +13,63 @@ def get_reports_folder_list(): return os.listdir(os.path.join(os.getcwd(), "reports")) -def refresh(navigation_panel): - for widget in navigation_panel.winfo_children(): +def refresh(self): + for widget in self.winfo_children(): widget.destroy() d = {} for report in get_reports_folder_list(): - d[report] = Report_Button(navigation_panel, report_name=report, - report_path=os.path.join(os.getcwd(), "reports", report)) - - navigation_panel.label = customtkinter.CTkLabel(navigation_panel, text="Reports List", - text_color=("#333", "#ccc"), - font=customtkinter.CTkFont(size=15, weight="bold")) - navigation_panel.label.grid(row=0, column=0, padx=20) + d[report] = Report_Frame(self, report_name=report, + report_path=os.path.join(os.getcwd(), "reports", report)) + self.label = customtkinter.CTkLabel(self, text="Reports List", + text_color=("#333", "#ccc"), + font=customtkinter.CTkFont(size=15, weight="bold")) + self.label.grid(row=0, column=0, padx=20) add_widgets(d, rowstart=1, columnstart=0, orientation="vertical") +def get_report_details(report_path): + number_of_rows = 0 + found_files = set() + try: + with open(os.path.join(report_path, 'report.csv'), 'r') as file: + reader = csv.reader(file) + next(reader, None) + for row in reader: + if not row[0] == "No Anydesk logs found!": + number_of_rows += 1 + found_files.add(row[2]) + except FileNotFoundError: + pass + + return {"number_of_rows": number_of_rows, "number_of_files": len(found_files)} + + +class Report_Frame(customtkinter.CTkFrame): + + def __init__(self, master, **kwargs): + super().__init__(master) + self.report_name = kwargs.get("report_name") + self.report_path = kwargs.get("report_path") + report_name_details = split_filename(self.report_name) + report_details = get_report_details(report_path=self.report_path) + self.grid_columnconfigure(0, weight=1) + + self.label = customtkinter.CTkLabel(self, text=report_name_details["date"] + " - " + + report_name_details["time"] + " - " + report_name_details[ + "computer_name"], + text_color=("#333", "#ccc") + ) + self.label.grid(row=0, column=0, sticky="ew", padx=20, pady=[10, 0]) + self.label2 = customtkinter.CTkLabel(self, text="Files: " + str(report_details["number_of_files"]) + " - " + + "IP Addresses: " + str(report_details["number_of_rows"]), + text_color=("#333", "#ccc") + ) + self.label2.grid(row=0, column=1, sticky="ew", padx=20, pady=[10, 0]) + + self.report_button = Report_Button(self, report_name=self.report_name, + report_path=os.path.join(os.getcwd(), "reports", self.report_path)) + + class Report_Button(customtkinter.CTkButton): def __init__(self, master, **kwargs): super().__init__(master) @@ -33,7 +77,9 @@ def __init__(self, master, **kwargs): self.report_name = kwargs.get("report_name") self.report_path = kwargs.get("report_path") - self.configure(text=self.report_name, command=self.open_report) + self.configure(text='Open Report', command=self.open_report, fg_color=("gray75", "gray25"), text_color=( + "#333", "#ccc"), hover_color=("#6ca9d4", "#1c3b50")) + self.grid(row=1, column=0, columnspan=2, sticky="ew", padx=20, pady=10) def open_report(self): os.startfile(self.report_path) @@ -48,13 +94,14 @@ def add_widgets(d, rowstart: int = 0, columnstart: int = 0, orientation: Literal value.grid(row=rowstart + i, column=columnstart + i, sticky="ew", padx=20, pady=10) -class Navigation_Panel(customtkinter.CTkScrollableFrame): +class Reports_List(customtkinter.CTkScrollableFrame): def __init__(self, master, **kwargs): super().__init__(master, **kwargs) self.grid(row=0, column=0, sticky="nsew") self.grid_columnconfigure(0, weight=1) + self.configure(fg_color="transparent") # add widgets onto the frame... refresh(self) @@ -67,8 +114,4 @@ def __init__(self, master, **kwargs): self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) - self.navigation_panel = Navigation_Panel(self) - - self.refresh_button = customtkinter.CTkButton(self, text="Refresh", - command=lambda: refresh(self.navigation_panel)) - self.refresh_button.grid(row=1, column=0, sticky="ew", padx=20, pady=10) + self.navigation_panel = Reports_List(self) diff --git a/main.py b/main.py index c4c5721..fd3438d 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,7 @@ from PIL import Image from frames.AnydeskFrame import AnydeskFrame -from frames.BrowseReportsFrame import BrowseReportsFrame +from frames.BrowseReportsFrame import BrowseReportsFrame, refresh from frames.HomeFrame import HomeFrame customtkinter.set_appearance_mode("System") @@ -136,6 +136,7 @@ def frame_2_button_event(self): def browse_reports_frame_button_event(self): """Browse Reports button event handler.""" self.select_frame_by_name("browse_reports_frame") + refresh(self=self.browse_reports_frame.navigation_panel) if __name__ == "__main__": diff --git a/utils/file_operations.py b/utils/file_operations.py index 21a49ed..ee42460 100644 --- a/utils/file_operations.py +++ b/utils/file_operations.py @@ -155,3 +155,12 @@ def generate_csv_report(report_directory_path: str, write_header: bool = True, a else: for entry in anydesk_logs_dict: writer.writerow([entry, anydesk_logs_dict[entry], filename]) + + +def split_filename(filename): + result = re.search(r"(.*)_(\d{2}-\d{2}-\d{4})_(\d{2}-\d{2}-\d{2}$)", filename) + return { + "computer_name": result.group(1), + "date": result.group(2), + "time": result.group(3) + } From 5f004724c50bb646560b3703f3c5617abe5a1398 Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Mon, 10 Apr 2023 20:40:58 +0200 Subject: [PATCH 04/13] Rename split_filename to more detailed 'split_computer_datetime_filename' Move get_reports_folder_list function to file_operations.py --- utils/file_operations.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/utils/file_operations.py b/utils/file_operations.py index ee42460..e82a22c 100644 --- a/utils/file_operations.py +++ b/utils/file_operations.py @@ -157,10 +157,18 @@ def generate_csv_report(report_directory_path: str, write_header: bool = True, a writer.writerow([entry, anydesk_logs_dict[entry], filename]) -def split_filename(filename): +def split_computer_datetime_filename(filename): result = re.search(r"(.*)_(\d{2}-\d{2}-\d{4})_(\d{2}-\d{2}-\d{2}$)", filename) return { "computer_name": result.group(1), "date": result.group(2), - "time": result.group(3) + "time": result.group(3).replace("-", ":") } + + +def get_reports_folder_list(): + try: + return os.listdir(os.path.join(os.getcwd(), "REPORTS")) + except FileNotFoundError: + os.mkdir(os.path.join(os.getcwd(), "REPORTS")) + return os.listdir(os.path.join(os.getcwd(), "REPORTS")) From f01cb89d5241cd075ab7945471e6435bc1c09f50 Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Mon, 10 Apr 2023 20:41:38 +0200 Subject: [PATCH 05/13] Move add_widgets to new widget_utils.py file --- frames/BrowseReportsFrame.py | 23 +++-------------------- utils/widget_utils.py | 10 ++++++++++ 2 files changed, 13 insertions(+), 20 deletions(-) create mode 100644 utils/widget_utils.py diff --git a/frames/BrowseReportsFrame.py b/frames/BrowseReportsFrame.py index 7afaca0..395cc09 100644 --- a/frames/BrowseReportsFrame.py +++ b/frames/BrowseReportsFrame.py @@ -1,16 +1,8 @@ import os import customtkinter -from typing import Literal import csv -from utils.file_operations import split_filename - - -def get_reports_folder_list(): - try: - return os.listdir(os.path.join(os.getcwd(), "reports")) - except FileNotFoundError: - os.mkdir(os.path.join(os.getcwd(), "reports")) - return os.listdir(os.path.join(os.getcwd(), "reports")) +from utils.file_operations import split_computer_datetime_filename, get_reports_folder_list +from utils.widget_utils import add_widgets def refresh(self): @@ -50,7 +42,7 @@ def __init__(self, master, **kwargs): super().__init__(master) self.report_name = kwargs.get("report_name") self.report_path = kwargs.get("report_path") - report_name_details = split_filename(self.report_name) + report_name_details = split_computer_datetime_filename(self.report_name) report_details = get_report_details(report_path=self.report_path) self.grid_columnconfigure(0, weight=1) @@ -85,15 +77,6 @@ def open_report(self): os.startfile(self.report_path) -def add_widgets(d, rowstart: int = 0, columnstart: int = 0, orientation: Literal["vertical", "horizontal"] = -"vertical"): - for i, (key, value) in enumerate(d.items()): - if orientation == "vertical": - value.grid(row=rowstart + i, column=columnstart, sticky="ew", padx=20, pady=10) - elif orientation == "horizontal": - value.grid(row=rowstart + i, column=columnstart + i, sticky="ew", padx=20, pady=10) - - class Reports_List(customtkinter.CTkScrollableFrame): def __init__(self, master, **kwargs): diff --git a/utils/widget_utils.py b/utils/widget_utils.py new file mode 100644 index 0000000..4b9ed3e --- /dev/null +++ b/utils/widget_utils.py @@ -0,0 +1,10 @@ +from typing import Literal + + +def add_widgets(d, rowstart: int = 0, columnstart: int = 0, orientation: Literal["vertical", "horizontal"] = +"vertical"): + for i, (key, value) in enumerate(d.items()): + if orientation == "vertical": + value.grid(row=rowstart + i, column=columnstart, sticky="ew", padx=20, pady=10) + elif orientation == "horizontal": + value.grid(row=rowstart + i, column=columnstart + i, sticky="ew", padx=20, pady=10) From 39c3d16495fa9d842d33dac04f40fd8755b0e839 Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Mon, 10 Apr 2023 21:35:39 +0200 Subject: [PATCH 06/13] Refactor the BrowseReportsFrame.py and associated functions --- frames/BrowseReportsFrame.py | 114 ++++++++++++++++++++--------------- main.py | 2 +- utils/file_operations.py | 8 ++- utils/widget_utils.py | 11 +++- 4 files changed, 82 insertions(+), 53 deletions(-) diff --git a/frames/BrowseReportsFrame.py b/frames/BrowseReportsFrame.py index 395cc09..b4d047a 100644 --- a/frames/BrowseReportsFrame.py +++ b/frames/BrowseReportsFrame.py @@ -1,49 +1,36 @@ +import csv import os import customtkinter -import csv + from utils.file_operations import split_computer_datetime_filename, get_reports_folder_list from utils.widget_utils import add_widgets -def refresh(self): - for widget in self.winfo_children(): - widget.destroy() - d = {} - for report in get_reports_folder_list(): - d[report] = Report_Frame(self, report_name=report, - report_path=os.path.join(os.getcwd(), "reports", report)) - self.label = customtkinter.CTkLabel(self, text="Reports List", - text_color=("#333", "#ccc"), - font=customtkinter.CTkFont(size=15, weight="bold")) - self.label.grid(row=0, column=0, padx=20) - add_widgets(d, rowstart=1, columnstart=0, orientation="vertical") - +class BrowseReportsFrame(customtkinter.CTkScrollableFrame): + """Browse Reports frame class holding the list of generated reports.""" -def get_report_details(report_path): - number_of_rows = 0 - found_files = set() - try: - with open(os.path.join(report_path, 'report.csv'), 'r') as file: - reader = csv.reader(file) - next(reader, None) - for row in reader: - if not row[0] == "No Anydesk logs found!": - number_of_rows += 1 - found_files.add(row[2]) - except FileNotFoundError: - pass - - return {"number_of_rows": number_of_rows, "number_of_files": len(found_files)} + def __init__(self, master, **kwargs): + super().__init__(master, **kwargs) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.configure(fg_color="transparent") + # add widgets onto the frame... + refresh(self) class Report_Frame(customtkinter.CTkFrame): + """A class representing a single report in the list of reports. + It shows the date, time and computer name of the report. + It also shows the number of files and IP addresses found in the report. + Button located in frame opens the report folder. + """ def __init__(self, master, **kwargs): super().__init__(master) self.report_name = kwargs.get("report_name") self.report_path = kwargs.get("report_path") report_name_details = split_computer_datetime_filename(self.report_name) - report_details = get_report_details(report_path=self.report_path) + report_details = get_report_file_and_ip_numbers(report_path=self.report_path) self.grid_columnconfigure(0, weight=1) self.label = customtkinter.CTkLabel(self, text=report_name_details["date"] + " - " + @@ -53,23 +40,26 @@ def __init__(self, master, **kwargs): ) self.label.grid(row=0, column=0, sticky="ew", padx=20, pady=[10, 0]) self.label2 = customtkinter.CTkLabel(self, text="Files: " + str(report_details["number_of_files"]) + " - " + - "IP Addresses: " + str(report_details["number_of_rows"]), + "IP Addresses: " + str( + report_details["number_of_ip_addresses"]), text_color=("#333", "#ccc") ) self.label2.grid(row=0, column=1, sticky="ew", padx=20, pady=[10, 0]) self.report_button = Report_Button(self, report_name=self.report_name, - report_path=os.path.join(os.getcwd(), "reports", self.report_path)) + report_path=os.path.join(os.getcwd(), "REPORTS", self.report_path)) class Report_Button(customtkinter.CTkButton): + """A class representing a button that opens the report folder.""" + def __init__(self, master, **kwargs): super().__init__(master) self.report_name = kwargs.get("report_name") self.report_path = kwargs.get("report_path") - self.configure(text='Open Report', command=self.open_report, fg_color=("gray75", "gray25"), text_color=( + self.configure(text='Open Report folder', command=self.open_report, fg_color=("gray75", "gray25"), text_color=( "#333", "#ccc"), hover_color=("#6ca9d4", "#1c3b50")) self.grid(row=1, column=0, columnspan=2, sticky="ew", padx=20, pady=10) @@ -77,24 +67,52 @@ def open_report(self): os.startfile(self.report_path) -class Reports_List(customtkinter.CTkScrollableFrame): +def refresh(browse_reports_frame_instance: customtkinter.CTkScrollableFrame): + """Function that refreshes the browse reports frame. + It deletes all widgets from the frame and adds new widgets. + It is used when new report is created so that the list of reports is updated. - def __init__(self, master, **kwargs): - super().__init__(master, **kwargs) + :param browse_reports_frame_instance: browse reports frame instance that will be refreshed with new data + """ - self.grid(row=0, column=0, sticky="nsew") - self.grid_columnconfigure(0, weight=1) - self.configure(fg_color="transparent") - # add widgets onto the frame... - refresh(self) + # delete all widgets from frame + for widget in browse_reports_frame_instance.winfo_children(): + widget.destroy() + reports_list = {} + # Get new list of reports and add dict entries representing a pair of: name of report and a frame with report + # details + for report in get_reports_folder_list(): + reports_list[report] = Report_Frame(browse_reports_frame_instance, report_name=report, + report_path=os.path.join(os.getcwd(), "REPORTS", report)) -class BrowseReportsFrame(customtkinter.CTkFrame): - """Browse Reports frame class.""" + # Add a top label to the list of reports + browse_reports_frame_instance.label = customtkinter.CTkLabel(browse_reports_frame_instance, text="Reports List", + text_color=("#333", "#ccc"), + font=customtkinter.CTkFont(size=15, weight="bold")) + browse_reports_frame_instance.label.grid(row=0, column=0, padx=20) + # Add all reports to the frame + add_widgets(reports_list, rowstart=1, columnstart=0, orientation="vertical") - def __init__(self, master, **kwargs): - super().__init__(master, **kwargs) - self.grid_columnconfigure(0, weight=1) - self.grid_rowconfigure(0, weight=1) - self.navigation_panel = Reports_List(self) +def get_report_file_and_ip_numbers(report_path): + """Function that returns the number of files and IP addresses found in the report by analyzing the report.csv file. + + :param report_path: path to the report folder + :return: dict with number of files and IP addresses found in the report + """ + + number_of_ip_addresses = 0 + found_files = set() + try: + with open(os.path.join(report_path, 'report.csv'), 'r') as file: + reader = csv.reader(file) + next(reader, None) + for row in reader: + if not row[0] == "No Anydesk logs found!": + number_of_ip_addresses += 1 + found_files.add(row[2]) + except FileNotFoundError: + pass + + return {"number_of_ip_addresses": number_of_ip_addresses, "number_of_files": len(found_files)} diff --git a/main.py b/main.py index fd3438d..a0230d2 100644 --- a/main.py +++ b/main.py @@ -136,7 +136,7 @@ def frame_2_button_event(self): def browse_reports_frame_button_event(self): """Browse Reports button event handler.""" self.select_frame_by_name("browse_reports_frame") - refresh(self=self.browse_reports_frame.navigation_panel) + refresh(browse_reports_frame_instance=self.browse_reports_frame) if __name__ == "__main__": diff --git a/utils/file_operations.py b/utils/file_operations.py index e82a22c..2ddb0cb 100644 --- a/utils/file_operations.py +++ b/utils/file_operations.py @@ -157,8 +157,9 @@ def generate_csv_report(report_directory_path: str, write_header: bool = True, a writer.writerow([entry, anydesk_logs_dict[entry], filename]) -def split_computer_datetime_filename(filename): - result = re.search(r"(.*)_(\d{2}-\d{2}-\d{4})_(\d{2}-\d{2}-\d{2}$)", filename) +def split_computer_datetime_filename(dirname): + """A function that splits a generated directory name into computer name, date and time""" + result = re.search(r"(.*)_(\d{2}-\d{2}-\d{4})_(\d{2}-\d{2}-\d{2}$)", dirname) return { "computer_name": result.group(1), "date": result.group(2), @@ -167,6 +168,9 @@ def split_computer_datetime_filename(filename): def get_reports_folder_list(): + """A function that returns a list of all directories in the REPORTS folder + Each directory name is a computer name and a timestamp and contains a report files, checksum and found logs + """ try: return os.listdir(os.path.join(os.getcwd(), "REPORTS")) except FileNotFoundError: diff --git a/utils/widget_utils.py b/utils/widget_utils.py index 4b9ed3e..af70e10 100644 --- a/utils/widget_utils.py +++ b/utils/widget_utils.py @@ -1,9 +1,16 @@ from typing import Literal -def add_widgets(d, rowstart: int = 0, columnstart: int = 0, orientation: Literal["vertical", "horizontal"] = +def add_widgets(widget_dict, rowstart: int = 0, columnstart: int = 0, orientation: Literal["vertical", "horizontal"] = "vertical"): - for i, (key, value) in enumerate(d.items()): + """ A function that adds widgets to a frame. + :param widget_dict: A dictionary containing the widgets to be added. + :param rowstart: The row number where the widgets will be added. + :param columnstart: The column number where the widgets will be added. + :param orientation: The orientation of the widgets. "vertical" or "horizontal". + """ + + for i, (key, value) in enumerate(widget_dict.items()): if orientation == "vertical": value.grid(row=rowstart + i, column=columnstart, sticky="ew", padx=20, pady=10) elif orientation == "horizontal": From 5f391deb9105ec2d05abfae37e32b62ddcc37c58 Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Mon, 10 Apr 2023 21:42:18 +0200 Subject: [PATCH 07/13] Update the name of split_computer_datetime_filename and add tests --- frames/BrowseReportsFrame.py | 4 ++-- tests/test_file_operations.py | 19 ++++++++++++++++++- utils/file_operations.py | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/frames/BrowseReportsFrame.py b/frames/BrowseReportsFrame.py index b4d047a..94bfe0b 100644 --- a/frames/BrowseReportsFrame.py +++ b/frames/BrowseReportsFrame.py @@ -2,7 +2,7 @@ import os import customtkinter -from utils.file_operations import split_computer_datetime_filename, get_reports_folder_list +from utils.file_operations import split_computer_datetime_dirname, get_reports_folder_list from utils.widget_utils import add_widgets @@ -29,7 +29,7 @@ def __init__(self, master, **kwargs): super().__init__(master) self.report_name = kwargs.get("report_name") self.report_path = kwargs.get("report_path") - report_name_details = split_computer_datetime_filename(self.report_name) + report_name_details = split_computer_datetime_dirname(self.report_name) report_details = get_report_file_and_ip_numbers(report_path=self.report_path) self.grid_columnconfigure(0, weight=1) diff --git a/tests/test_file_operations.py b/tests/test_file_operations.py index c1869ae..af2da1b 100644 --- a/tests/test_file_operations.py +++ b/tests/test_file_operations.py @@ -3,7 +3,8 @@ import shutil from datetime import datetime from utils.file_operations import get_anydesk_logs, create_timestamped_directory, create_folders_from_path, \ - generate_md5_file_checksum, copy_and_generate_checksum, generate_txt_report, generate_csv_report + generate_md5_file_checksum, copy_and_generate_checksum, generate_txt_report, generate_csv_report, \ + split_computer_datetime_dirname import os import re import sys @@ -230,3 +231,19 @@ def test_generate_empty_csv_report(self): # assert assert actual_output == expected_output os.remove(os.path.join(report_directory_path, 'report.csv')) + + +def test_split_computer_datetime_dirname(): + assert split_computer_datetime_dirname('computer_11-03-2023_19-09-48') == {'computer_name': 'computer', + 'date': '11-03-2023', 'time': '19:09:48'} + + assert split_computer_datetime_dirname('test_computer--203;lk;asdfj_11-03-2023_19-09-48') == { + 'computer_name': 'test_computer--203;lk;asdfj', + 'date': '11-03-2023', 'time': '19:09:48'} + + assert split_computer_datetime_dirname('1234567890_11-03-2023_19-09-48') == { + 'computer_name': '1234567890', + 'date': '11-03-2023', 'time': '19:09:48'} + + assert split_computer_datetime_dirname('__11-03-2023_19-09-48') == {'computer_name': '_', + 'date': '11-03-2023', 'time': '19:09:48'} diff --git a/utils/file_operations.py b/utils/file_operations.py index 2ddb0cb..f7441c6 100644 --- a/utils/file_operations.py +++ b/utils/file_operations.py @@ -157,7 +157,7 @@ def generate_csv_report(report_directory_path: str, write_header: bool = True, a writer.writerow([entry, anydesk_logs_dict[entry], filename]) -def split_computer_datetime_filename(dirname): +def split_computer_datetime_dirname(dirname): """A function that splits a generated directory name into computer name, date and time""" result = re.search(r"(.*)_(\d{2}-\d{2}-\d{4})_(\d{2}-\d{2}-\d{2}$)", dirname) return { From 366bbafcf6b8b6d0398920f1c68a40618197bfa4 Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Tue, 11 Apr 2023 18:51:14 +0200 Subject: [PATCH 08/13] Add check for invalid folder names in report folder --- frames/BrowseReportsFrame.py | 15 ++++++++++----- tests/test_file_operations.py | 4 ++++ utils/file_operations.py | 13 ++++++++----- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/frames/BrowseReportsFrame.py b/frames/BrowseReportsFrame.py index 94bfe0b..7ca8aa4 100644 --- a/frames/BrowseReportsFrame.py +++ b/frames/BrowseReportsFrame.py @@ -33,11 +33,16 @@ def __init__(self, master, **kwargs): report_details = get_report_file_and_ip_numbers(report_path=self.report_path) self.grid_columnconfigure(0, weight=1) - self.label = customtkinter.CTkLabel(self, text=report_name_details["date"] + " - " + - report_name_details["time"] + " - " + report_name_details[ - "computer_name"], - text_color=("#333", "#ccc") - ) + if report_name_details: + self.label = customtkinter.CTkLabel(self, text=report_name_details["date"] + " - " + + report_name_details["time"] + " - " + report_name_details[ + "computer_name"], + text_color=("#333", "#ccc") + ) + else: + self.label = customtkinter.CTkLabel(self, text=self.report_name, + text_color=("#333", "#ccc") + ) self.label.grid(row=0, column=0, sticky="ew", padx=20, pady=[10, 0]) self.label2 = customtkinter.CTkLabel(self, text="Files: " + str(report_details["number_of_files"]) + " - " + "IP Addresses: " + str( diff --git a/tests/test_file_operations.py b/tests/test_file_operations.py index af2da1b..00705e5 100644 --- a/tests/test_file_operations.py +++ b/tests/test_file_operations.py @@ -247,3 +247,7 @@ def test_split_computer_datetime_dirname(): assert split_computer_datetime_dirname('__11-03-2023_19-09-48') == {'computer_name': '_', 'date': '11-03-2023', 'time': '19:09:48'} + + assert split_computer_datetime_dirname('asfdfasd') is None + assert split_computer_datetime_dirname('asfdfasd_11-03-2023_12-dd-22') is None + assert split_computer_datetime_dirname('asfdfasd_11-03-2023_bb-dd-ee') is None diff --git a/utils/file_operations.py b/utils/file_operations.py index f7441c6..ab1d55f 100644 --- a/utils/file_operations.py +++ b/utils/file_operations.py @@ -160,11 +160,14 @@ def generate_csv_report(report_directory_path: str, write_header: bool = True, a def split_computer_datetime_dirname(dirname): """A function that splits a generated directory name into computer name, date and time""" result = re.search(r"(.*)_(\d{2}-\d{2}-\d{4})_(\d{2}-\d{2}-\d{2}$)", dirname) - return { - "computer_name": result.group(1), - "date": result.group(2), - "time": result.group(3).replace("-", ":") - } + if result: + return { + "computer_name": result.group(1), + "date": result.group(2), + "time": result.group(3).replace("-", ":") + } + else: + return None def get_reports_folder_list(): From fea3f4c81dd3bba05be61560a42e053a7c10d18f Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Wed, 12 Apr 2023 21:01:48 +0200 Subject: [PATCH 09/13] Add tests for get_reports_folder_list --- tests/test_file_operations.py | 19 ++++++++++++++++++- utils/file_operations.py | 13 +++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/tests/test_file_operations.py b/tests/test_file_operations.py index 00705e5..f7d17d4 100644 --- a/tests/test_file_operations.py +++ b/tests/test_file_operations.py @@ -4,7 +4,7 @@ from datetime import datetime from utils.file_operations import get_anydesk_logs, create_timestamped_directory, create_folders_from_path, \ generate_md5_file_checksum, copy_and_generate_checksum, generate_txt_report, generate_csv_report, \ - split_computer_datetime_dirname + split_computer_datetime_dirname, get_reports_folder_list import os import re import sys @@ -251,3 +251,20 @@ def test_split_computer_datetime_dirname(): assert split_computer_datetime_dirname('asfdfasd') is None assert split_computer_datetime_dirname('asfdfasd_11-03-2023_12-dd-22') is None assert split_computer_datetime_dirname('asfdfasd_11-03-2023_bb-dd-ee') is None + + +def test_get_reports_folder_list(tmp_path): + reports_folder = os.path.join(tmp_path, 'REPORTS') + # Assert that the reports folder does not exist + assert not os.path.isdir(reports_folder) + # Assert that after running the function the reports folder is created and is empty + assert get_reports_folder_list(reports_folder) == [] + # Assert that the reports folder exists + assert os.path.isdir(reports_folder) + assert os.path.exists(os.path.join(tmp_path, 'REPORTS')) + os.mkdir(os.path.join(reports_folder, 'computer_11-03-2023_19-09-48')) + os.mkdir(os.path.join(reports_folder, 'computer_11-03-2023_19-09-49')) + os.mkdir(os.path.join(reports_folder, 'computer_11-03-2023_19-09-50')) + assert get_reports_folder_list(reports_folder) == ['computer_11-03-2023_19-09-48', + 'computer_11-03-2023_19-09-49', + 'computer_11-03-2023_19-09-50'] diff --git a/utils/file_operations.py b/utils/file_operations.py index ab1d55f..13e148d 100644 --- a/utils/file_operations.py +++ b/utils/file_operations.py @@ -170,12 +170,13 @@ def split_computer_datetime_dirname(dirname): return None -def get_reports_folder_list(): - """A function that returns a list of all directories in the REPORTS folder - Each directory name is a computer name and a timestamp and contains a report files, checksum and found logs +def get_reports_folder_list(reports_directory='REPORTS'): + """A function that returns a list of all directories in the current working directory/reports_directory folder + If the folder does not exist, it will be created + :param reports_directory: a name of reports folder inside current working directory """ try: - return os.listdir(os.path.join(os.getcwd(), "REPORTS")) + return os.listdir(os.path.join(os.getcwd(), reports_directory)) except FileNotFoundError: - os.mkdir(os.path.join(os.getcwd(), "REPORTS")) - return os.listdir(os.path.join(os.getcwd(), "REPORTS")) + os.mkdir(os.path.join(os.getcwd(), reports_directory)) + return os.listdir(os.path.join(os.getcwd(), reports_directory)) From 6ee4feabf0a0f68d7b8ac47bd799495b70ac680e Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Wed, 12 Apr 2023 22:15:06 +0200 Subject: [PATCH 10/13] Test IO Errors in copy_and_generate_checksum --- tests/test_file_operations.py | 9 ++++++++- utils/file_operations.py | 2 -- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/test_file_operations.py b/tests/test_file_operations.py index f7d17d4..62e7976 100644 --- a/tests/test_file_operations.py +++ b/tests/test_file_operations.py @@ -127,7 +127,7 @@ def test_generate_md5_file_checksum(self): assert generate_md5_file_checksum(test_file) == test_file_hash os.remove('test_file.txt') - def test_copy_and_generate_checksum(self): + def test_copy_and_generate_checksum(self, capsys): test_file = TestGetAnydeskLogs.create_empty_file('test_file.txt') test_file_hash = hashlib.md5(open('test_file.txt', 'rb').read()).hexdigest() cwd = os.getcwd() @@ -140,6 +140,13 @@ def test_copy_and_generate_checksum(self): shutil.rmtree(os.path.join(os.getcwd(), 'REPORTS')) os.remove('test_file.txt') + # Test IOError + nonexistent_file = 'nonexistent_file.txt' + path_to_nonexistent_file = os.path.join(os.getcwd(), nonexistent_file) + copy_and_generate_checksum(path_to_nonexistent_file, os.getcwd()) + captured_error_print = capsys.readouterr() + assert captured_error_print.out == 'Error occurred when trying to copy\n' + class TestGeneratingTextReport: def test_generate_txt_report_with_header(self): diff --git a/utils/file_operations.py b/utils/file_operations.py index 13e148d..bb216ed 100644 --- a/utils/file_operations.py +++ b/utils/file_operations.py @@ -101,8 +101,6 @@ def generate_md5_file_checksum(filename: str) -> str: file_hash = hashlib.md5() while chunk := f.read(8192): file_hash.update(chunk) - # print(file_hash.digest()) - # print(file_hash.hexdigest()) # to get a printable str instead of bytes return file_hash.hexdigest() From 8744f22869d5a971433d8531e78ccf1514028c1a Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Wed, 12 Apr 2023 22:15:31 +0200 Subject: [PATCH 11/13] Test getcomputername with monkeypatch --- tests/test_file_operations.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/test_file_operations.py b/tests/test_file_operations.py index 62e7976..7990ae2 100644 --- a/tests/test_file_operations.py +++ b/tests/test_file_operations.py @@ -1,10 +1,13 @@ +import pytest import csv import hashlib import shutil +import socket from datetime import datetime + from utils.file_operations import get_anydesk_logs, create_timestamped_directory, create_folders_from_path, \ generate_md5_file_checksum, copy_and_generate_checksum, generate_txt_report, generate_csv_report, \ - split_computer_datetime_dirname, get_reports_folder_list + split_computer_datetime_dirname, get_reports_folder_list, get_computer_name import os import re import sys @@ -275,3 +278,28 @@ def test_get_reports_folder_list(tmp_path): assert get_reports_folder_list(reports_folder) == ['computer_11-03-2023_19-09-48', 'computer_11-03-2023_19-09-49', 'computer_11-03-2023_19-09-50'] + + +def test_linux_computer(monkeypatch): + monkeypatch.setattr(sys, 'platform', 'Linux') + monkeypatch.setattr(socket, 'getfqdn', lambda: 'Test_Computer_Linux') + assert get_computer_name() == "Test_Computer_Linux" + + +def test_windows_computer(monkeypatch): + monkeypatch.setattr(sys, 'platform', 'Windows') + monkeypatch.setitem(os.environ, "COMPUTERNAME", "Test_Computer") + assert get_computer_name() == "Test_Computer" + + +def test_mac_computer(monkeypatch): + monkeypatch.setattr(sys, 'platform', 'Darwin') + monkeypatch.setattr(socket, 'gethostname', lambda: 'Test_Computer_Mac') + assert get_computer_name() == "Test_Computer_Mac" + + +def test_unknown_computer(monkeypatch): + monkeypatch.setattr(sys, 'platform', 'Unknown') + with pytest.raises(Exception) as exception_info: + get_computer_name() + assert 'Operating system not supported' in str(exception_info.value) From f5ddfd04475586570acb3a27b754346c31fc22bb Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Thu, 20 Apr 2023 22:03:55 +0200 Subject: [PATCH 12/13] Rework test_get_reports_folder_list and scrap testing os --- tests/test_file_operations.py | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/tests/test_file_operations.py b/tests/test_file_operations.py index 7990ae2..4c0e136 100644 --- a/tests/test_file_operations.py +++ b/tests/test_file_operations.py @@ -1,13 +1,11 @@ -import pytest import csv import hashlib import shutil -import socket from datetime import datetime from utils.file_operations import get_anydesk_logs, create_timestamped_directory, create_folders_from_path, \ generate_md5_file_checksum, copy_and_generate_checksum, generate_txt_report, generate_csv_report, \ - split_computer_datetime_dirname, get_reports_folder_list, get_computer_name + split_computer_datetime_dirname, get_reports_folder_list import os import re import sys @@ -277,29 +275,8 @@ def test_get_reports_folder_list(tmp_path): os.mkdir(os.path.join(reports_folder, 'computer_11-03-2023_19-09-50')) assert get_reports_folder_list(reports_folder) == ['computer_11-03-2023_19-09-48', 'computer_11-03-2023_19-09-49', - 'computer_11-03-2023_19-09-50'] - - -def test_linux_computer(monkeypatch): - monkeypatch.setattr(sys, 'platform', 'Linux') - monkeypatch.setattr(socket, 'getfqdn', lambda: 'Test_Computer_Linux') - assert get_computer_name() == "Test_Computer_Linux" - - -def test_windows_computer(monkeypatch): - monkeypatch.setattr(sys, 'platform', 'Windows') - monkeypatch.setitem(os.environ, "COMPUTERNAME", "Test_Computer") - assert get_computer_name() == "Test_Computer" - - -def test_mac_computer(monkeypatch): - monkeypatch.setattr(sys, 'platform', 'Darwin') - monkeypatch.setattr(socket, 'gethostname', lambda: 'Test_Computer_Mac') - assert get_computer_name() == "Test_Computer_Mac" - - -def test_unknown_computer(monkeypatch): - monkeypatch.setattr(sys, 'platform', 'Unknown') - with pytest.raises(Exception) as exception_info: - get_computer_name() - assert 'Operating system not supported' in str(exception_info.value) + 'computer_11-03-2023_19-09-50'] \ + or get_reports_folder_list( + reports_folder) == ['computer_11-03-2023_19-09-50', + 'computer_11-03-2023_19-09-49', + 'computer_11-03-2023_19-09-48'] From 936eaae9e138a253e8ad3660cca069f1ceda731f Mon Sep 17 00:00:00 2001 From: Krzysztof Pantak Date: Thu, 20 Apr 2023 22:09:14 +0200 Subject: [PATCH 13/13] Update testing function for get folders list --- tests/test_file_operations.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/test_file_operations.py b/tests/test_file_operations.py index 4c0e136..9908415 100644 --- a/tests/test_file_operations.py +++ b/tests/test_file_operations.py @@ -273,10 +273,6 @@ def test_get_reports_folder_list(tmp_path): os.mkdir(os.path.join(reports_folder, 'computer_11-03-2023_19-09-48')) os.mkdir(os.path.join(reports_folder, 'computer_11-03-2023_19-09-49')) os.mkdir(os.path.join(reports_folder, 'computer_11-03-2023_19-09-50')) - assert get_reports_folder_list(reports_folder) == ['computer_11-03-2023_19-09-48', - 'computer_11-03-2023_19-09-49', - 'computer_11-03-2023_19-09-50'] \ - or get_reports_folder_list( - reports_folder) == ['computer_11-03-2023_19-09-50', - 'computer_11-03-2023_19-09-49', - 'computer_11-03-2023_19-09-48'] + assert sorted(get_reports_folder_list(reports_folder)) == sorted(['computer_11-03-2023_19-09-48', + 'computer_11-03-2023_19-09-49', + 'computer_11-03-2023_19-09-50'])