SyncTk/classes/frames/device.py

150 lines
7.5 KiB
Python

import platform
from datetime import datetime
from functools import partial
from tkinter import LEFT, NSEW, E, Misc, W, messagebox, ttk
from tkinter.messagebox import askyesno
from urllib.parse import quote, urlencode
import requests
from classes.custom.themed_frame import ThemedFrame
from modules.logger import logger
from modules.utils import configGet, configSet, osname
class FrameDevice(ThemedFrame):
def __init__(self, master: Misc, device_dict: str, **kwargs) -> None:
super().__init__(master, style="Card.TFrame", **kwargs)
self.widget_width = 47 if osname == "nt" else 42
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=3)
self.grid_columnconfigure(2, weight=3)
self.name = device_dict["name"]
self.title = ttk.Label(self, text=self.name, font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=self.widget_width)
self.title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
last_upload = "N/A" if device_dict["last_save"] == 0 else datetime.utcfromtimestamp(device_dict["last_save"]).strftime("%d.%m.%Y %H:%M")
self.description = ttk.Label(self, text=f'OS: {device_dict["os"]}\nClient: {device_dict["client"]}\nLast upload: {last_upload}', width=self.widget_width)
self.description.grid(column=0, row=1, padx=9, pady=9, sticky=W)
self.buttons = ThemedFrame(self)
self.buttons.grid(column=0, columnspan=2, row=2, sticky=NSEW, padx=9, pady=9)
self.buttons.grid_columnconfigure(0, weight=1)
self.button_device_rename_action = partial(self.rename)
self.button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=self.button_device_rename_action)
self.button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
self.button_device_delete_action = partial(self.delete)
self.button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=self.button_device_delete_action)
self.button_device_delete.grid(column=1, row=0, sticky=W)
if self.name == configGet("name"):
self.button_device_delete.state(["disabled"])
def rename(self):
self.rename_entry = ttk.Entry(self, font=("SunValleyBodyFont", 12), justify=LEFT, width=27)
self.rename_entry.insert(0, self.name)
self.rename_entry.grid(column=0, row=0, padx=9, pady=9, sticky=W)
button_device_cancel_action = partial(self.rename_cancel)
button_device_cancel = ttk.Button(self.buttons, text="Cancel", width=11, command=button_device_cancel_action)
button_device_cancel.grid(column=0, row=0, padx=9, sticky=E)
button_device_save_action = partial(self.rename_verify)
button_device_save = ttk.Button(self.buttons, text="Save", style="Accent.TButton", width=11, command=button_device_save_action)
button_device_save.grid(column=1, row=0, sticky=W)
def rename_verify(self):
self.name_before = configGet("name")
if (self.rename_entry.get().strip() == "") or ("?" in self.rename_entry.get().strip()) or ("/" in self.rename_entry.get().strip()):
logger.error(f"Name {self.rename_entry.get().strip()} is not a valid name")
messagebox.showerror(title="Name error", message="Provided device name is not valid. Please provide a valid one.")
return
try:
quote(self.rename_entry.get().strip())
except:
logger.error(f"Name {self.rename_entry.get().strip()} is not a valid name")
messagebox.showerror(title="Name error", message="Provided device name is not valid. Please provide a valid one.")
return
existing_device_before = requests.get(f'{configGet("address")}/devices/{self.name}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
if existing_device_before.status_code == 200:
response = requests.patch(f'{configGet("address")}/devices/{self.name}?{urlencode({"new_name": self.rename_entry.get().strip(), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.master.master.master.__version__}"})}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
if response.status_code != 204:
logger.error(f"Name {self.rename_entry.get().strip()} could not be set because server returned {response.status_code}")
messagebox.showerror(title="Name error", message=f"Provided device name is not valid.\n\nServer response: {response.json()}")
return
else:
logger.error(f"Tried to rename {self.name} into {self.rename_entry.get().strip()} but server returned {existing_device_before.status_code}")
messagebox.showerror(title="Rename error", message="It seems like this device no longer exists.")
return
self.name = self.rename_entry.get().strip()
for widget in self.winfo_children():
if isinstance(widget, ttk.Entry):
widget.destroy()
device_title = ttk.Label(self, text=self.name, font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=self.widget_width)
device_title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
button_device_rename_action = partial(self.rename)
button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=button_device_rename_action)
button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
button_device_delete_action = partial(self.delete)
button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=button_device_delete_action)
button_device_delete.grid(column=1, row=0, sticky=W)
if self.name_before == configGet("name"):
configSet(["name"], self.name)
if self.name == configGet("name"):
button_device_delete.state(["disabled"])
def rename_cancel(self):
for widget in self.winfo_children():
if isinstance(widget, ttk.Entry):
widget.destroy()
device_title = ttk.Label(self, text=self.name, font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=self.widget_width)
device_title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
button_device_rename_action = partial(self.rename)
button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=button_device_rename_action)
button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
button_device_delete_action = partial(self.delete)
button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=button_device_delete_action)
button_device_delete.grid(column=1, row=0, sticky=W)
if self.name == configGet("name"):
button_device_delete.state(["disabled"])
def delete(self):
decision = askyesno(title="Device removal", message=f"You are about to remove the device '{self.name}' and this will also remove all the save files uploaded by this device. Are you sure you want to continue?")
if decision is False:
return
requests.delete(f'{configGet("address")}/devices/{self.name}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
for k in range(len(self.master.devices)):
if self.master.devices[k]["name"] == self.name:
del self.master.devices[k]
break
self.destroy()