import base64 import hashlib from datetime import datetime from typing import Union import xml.etree.ElementTree as ET import requests from django.conf import settings from app_be.services.StorageServiceInterface import StorageServiceInterface class MinioService(StorageServiceInterface): name = "MinIO" @staticmethod def get_last_modified(filename: str): """Get last modified time of file :param filename: filename :return: Date of last modification or None """ try: r = requests.get(settings.AWS_HOST + "?prefix="+filename) root = ET.fromstring(r.content) for child in root.iter('{http://s3.amazonaws.com/doc/2006-03-01/}Contents'): if child.find('{http://s3.amazonaws.com/doc/2006-03-01/}Key').text == filename: date_time_str = child.find('{http://s3.amazonaws.com/doc/2006-03-01/}LastModified').text print(date_time_str) date_time_obj = datetime.strptime(date_time_str, '%Y-%m-%dT%H:%M:%S.%fZ') return date_time_obj except: return None return None @staticmethod def check() -> bool: print("Checking MinIO availability") try: url = settings.AWS_HOST r = requests.put(url) if not (200 <= r.status_code < 500): return False except: return False return True @staticmethod def create_file(filename: str, file: bytes) -> bool: """Create / save (or overwrite) an file on the minio storage. :param filename: filename :param file: bytes representation of the file :return: Whether file was successfully uploaded """ try: url = settings.AWS_HOST + filename headers = {'Content-Type': 'binary/octet-stream'} r = requests.put(url, data=file, headers=headers) if r.status_code == 200: print("Successfully uploaded a file!") else: print("Something went wrong while creating") except: return False return True @staticmethod def move_file(identifier_from: str, identifier_to: str, file: bytes) -> bool: """Move/Rename a file on the S3 storage. Consists of a PUT method (copying the object) and a delete method. :param identifier_from: Location of the file to be moved :param identifier_to: Location the file should be moved to :return True on success, False otherwise """ print("MinioService: Trying to move/rename file from {} to {}".format(identifier_from, identifier_to)) filename_from = identifier_from + '.jpg' filename_to = identifier_to if not MinioService.delete_file(filename_from): print("MinioService: Updating (delete) file {} failed".format(filename_from)) return False if not MinioService.create_file(filename_to, file): print("MinioService: Updating (create) file {} failed".format(filename_to)) return False return True @staticmethod def read_file(filename: str) -> bytes: """Read file on the minio storage. :param filename: filename :return: bytes representation of the file or None on error """ file_bytes: Union[bytes, None] = None try: url = settings.AWS_HOST + filename response = requests.get(url, stream=True) if response.status_code == 404: return file_bytes file_bytes = response.content except: print("Error downloading file from minio") return file_bytes @staticmethod def delete_file(filename: str) -> bool: """Delete an file from the dropbox storage. :param filename: filename of the file :return: Whether file was successfully deleted """ try: url = settings.AWS_HOST + filename r = requests.delete(url) if r.status_code == 204: print("Successfully deleted a file!") else: print("Something went wrong while deleting") except: return False return True @staticmethod def delete_all() -> bool: """Delete every file from the dropbox storage. :return: Whether the storage was successfully emptied """ try: r = requests.get(settings.AWS_HOST + "?list") root = ET.fromstring(r.content) list = [] cnt = 0 for child in root.iter('{http://s3.amazonaws.com/doc/2006-03-01/}Contents'): list.append(child.find('{http://s3.amazonaws.com/doc/2006-03-01/}Key').text) cnt = cnt + 1 if cnt == 0: return True body = "" for key in list: body += "" + key + "" body += "" print(body) header = {"Content-MD5": base64.b64encode(hashlib.md5(body.encode()).digest()), 'Content-Type': 'binary/application/xml'} r = requests.post(settings.AWS_HOST + "?delete", data=body, headers=header) if r.status_code == 200: print("Successfully deleted all files!") else: print("Something went wrong by deleting", r.status_code, r.content) exit() except: return False return True