import sqlite3 import pathlib import uuid from typing import Union, Optional from contentmonster.classes.file import File as ContentMonsterFile from contentmonster.classes.directory import Directory as ContentMonsterDirectory from contentmonster.classes.vessel import Vessel as ContentMonsterVessel from ..models.replication import ReplicationFile, ReplicationSource, ReplicationFileLog, ReplicationTarget class ContentMonsterDatabase: """Class wrapping Django database for ContentMonster """ def commit(self) -> None: """noop """ pass def getFileUUID(self, fileobj: ContentMonsterFile) -> str: """Retrieve unique identifier for ContentMonsterFile object Args: fileobj (ContentMonsterFile): ContentMonsterFile object to retrieve UUID for Returns: str: UUID for passed ContentMonsterFile object """ hash = fileobj.getHash() files = ReplicationFile.objects.filter(directory__name=fileobj.directory.name, name=fileobj.name) # If file with same name and directory exists for result in files: # If it has the same hash, it is the same file -> return its UUID if file.checksum == hash: fileuuid = result.uuid # If not, it is a file that can no longer exist -> delete it else: self.removeFileByUUID(result.uuid) # Return found UUID or generate a new one return fileuuid or self.addFile(fileobj, hash) def addFile(self, fileobj: ContentMonsterFile, hash: Optional[str] = None) -> str: """Adds a new ReplicationFile object to the database Args: fileobj (ContentMonsterFile): ContentMonsterFile object to add to database hash (str, optional): Checksum of the file, if already known. Defaults to None and will use .getHash() to calculate checksum then. Returns: str: UUID of the new ContentMonsterFile record """ hash = hash or fileobj.getHash() fileuuid = str(uuid.uuid4()) directory = ReplicationSource.objects.get(name=fileobj.directory.name) ReplicationFile.objects.create(uuid=fileuuid, directory=directory, name=fileobj.name, checksum=hash) return fileuuid def getFileByUUID(self, fileuuid: str) -> Optional[tuple[str, str, str]]: """Get additional information on a ContentMonsterFile by its UUID Args: fileuuid (str): The UUID of the ReplicationFile to retrieve from the database Returns: tuple: A tuple consisting of (directory, name, checksum), where "directory" is the name of the Directory object the File is located in, "name" is the filename (basename) of the File and checksum is the SHA256 hash of the file at the time of insertion into the database. None is returned if no such record is found. """ try: result = ReplicationFile.objects.get(uuid=fileuuid) return (result.directory.name, result.name, result.checksum) except ReplicationFile.DoesNotExist: return None def removeFile(self, directory: ContentMonsterDirectory, name: str) -> None: """Remove a ReplicationFile from the database based on ContentMonsterDirectory and filename Args: directory (ContentMonsterDirectory): ContentMonsterDirectory object containing the ContentMonsterFile to remove name (str): Filename of the ContentMonsterFile to remove """ ReplicationFile.objects.filter(directory__name=directory.name, name=name).delete() def removeFileByUUID(self, fileuuid: str) -> None: """Remove a ReplicationFile from the database based on UUID Args: fileuuid (str): The UUID of the ContentMonsterFile to remove from the database """ ReplicationFile.objects.filter(uuid=fileuuid).delete() def logCompletion(self, file: ContentMonsterFile, vessel: ContentMonsterVessel): """Log the completion of a ContentMonsterFile upload Args: file (ContentMonsterFile): The ContentMonsterFile object that has been uploaded vessel (ContentMonsterVessel): The ContentMonsterVessel the File has been uploaded to """ fileobj = ReplicationFile.objects.get(uuid=file.uuid) vesselobj = ReplicationTarget.objects.get(name=vessel.name) ReplicationFileLog.objects.create(file=fileobj, vessel=vesselobj) def getCompletionForVessel(self, vessel: ContentMonsterVessel) -> list[Optional[str]]: """Get completed uploads for a vessel Args: vessel (ContentMonsterVessel): The ContentMonsterVessel object to retrieve uploaded files for Returns: list: List of UUIDs of ContentMonsterFiles that have been successfully uploaded """ vesselobj = ReplicationTarget.objects.get(name=vessel.name) objects = ReplicationFileLog.objects.filter(vessel=vesselobj) return [o.file.uuid for o in objects] def getCompletionByFileUUID(self, fileuuid: str) -> list[Optional[str]]: objects = ReplicationFileLog.objects.filter(file__uuid=fileuuid) return [o.vessel.name for o in objects] def migrate(self) -> None: """noop """ pass def __del__(self): """noop """ pass