from __future__ import annotations import base64 import datetime import hashlib import os import uuid import dateutil import dateutil.tz import file_widgets import pydantic from PyQt6.QtGui import QIcon from PyQt6.QtWidgets import QFileDialog, QLabel, QMessageBox, QWidget from request_client import RequestClient from utils import resource_path class File(pydantic.BaseModel): file_id: uuid.UUID file_name: str file_size: int sha512: str created_at: datetime.datetime updated_at: datetime.datetime def name(self) -> str: return self.file_name def delete(self) -> None: RequestClient().client.delete( "/files", params={"file_id": self.file_id} ) def details(self, list: file_widgets.FileListWidget) -> QWidget: del list file_size = self._format_size(self.file_size) file_size_text = f"{file_size[0]:.2f} {file_size[1]}" created_at = self._format_date(self.created_at) updated_at = self._format_date(self.updated_at) details = ( f"file id: {self.file_id}\nfile_name: {self.file_name}\n" + f"file_size: {file_size_text}\n" + f"created at: {created_at}\nupdated at: {updated_at}" ) label = QLabel() label.setWindowTitle("File info") label.setText(details) return label @staticmethod def _format_size(size: int): power = 2**10 n = 0 power_labels = {0: "", 1: "kibi", 2: "mebi", 3: "gibi", 4: "tebi"} while size > power and n < 4: size /= power n += 1 return size, power_labels[n] + "bytes" @staticmethod def _format_date(date: datetime.datetime) -> str: date = date.replace(tzinfo=dateutil.tz.tzutc()) date = date.astimezone(dateutil.tz.tzlocal()) return date.strftime("%Y-%m-%d %H:%M:%S") def icon(self) -> QIcon: return QIcon(resource_path("assets/file.png")) def double_click(self, list: file_widgets.FileListWidget) -> None: location = QFileDialog.getExistingDirectory( list, caption="Select save location" ) if not location: return with open( os.path.join(location, self.file_name), "wb" ) as f, RequestClient().client.stream( "GET", "/files", params={"file_id": self.file_id} ) as stream: if not stream.is_success: QMessageBox.warning(list, "Error downloading the file") return for data in stream.iter_bytes(): f.write(data) def create(path: str, parent_id: uuid.UUID): """Upload the file""" print(path) file_name = os.path.basename(path) try: with open(path, "rb") as f: files = {"file": (file_name, f)} response = RequestClient().client.post( "/files", files=files, params={"parent_folder": parent_id}, ) if not response.is_success: QMessageBox.warning( None, "Error", f"Upload failed: {response.text}" ) print(response.text) except Exception as e: QMessageBox.critical(None, "HTTP Error", str(e)) def download(self, path: str): try: with open(path, "wb") as f, RequestClient().client.stream( "GET", "/files", params={"file_id": self.file_id} ) as stream: if not stream.is_success: QMessageBox.warning( None, "Error downloading the file", "Error downloading the file", ) return for data in stream.iter_bytes(): f.write(data) except Exception as e: QMessageBox.warning(None, "Error downloading the file", str(e)) def modify(self, path: str): """Upload the file""" file_name = os.path.basename(path) hash = hashlib.file_digest(open(path, "rb"), "sha512").digest() if base64.b64decode(self.sha512) == hash: return try: with open(path, "rb") as f: files = {"file": (file_name, f)} response = RequestClient().client.patch( "/files", files=files, params={"file_id": self.file_id}, ) if not response.is_success: QMessageBox.warning( None, "Error", f"Upload failed: {response.text}" ) except Exception as e: QMessageBox.critical(None, "HTTP Error", str(e))