diff --git a/one_backup_manager/hooks.py b/one_backup_manager/hooks.py index 381aca5..00de80d 100644 --- a/one_backup_manager/hooks.py +++ b/one_backup_manager/hooks.py @@ -118,7 +118,7 @@ # "one_backup_manager.tasks.all" # ], "daily": [ - "one_backup_manager.one_backup_manager.doctype.one_backup_settings.one_backup_settings.create_backup" + "one_backup_manager.one_backup_manager.doctype.one_backup_settings.one_backup_settings.auto_backup_to_gdrive" ], # "hourly": [ # "one_backup_manager.tasks.hourly" diff --git a/one_backup_manager/one_backup_manager/doctype/backup_log/__init__.py b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/__init__.py similarity index 100% rename from one_backup_manager/one_backup_manager/doctype/backup_log/__init__.py rename to one_backup_manager/one_backup_manager/doctype/gdrive_upload/__init__.py diff --git a/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.js b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.js new file mode 100644 index 0000000..fe81eed --- /dev/null +++ b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.js @@ -0,0 +1,19 @@ +// Copyright (c) 2023, ONE FM and contributors +// For license information, please see license.txt + +frappe.ui.form.on('GDrive Upload', { + upload: function(frm) { + frappe.call({ + doc: frm.doc, + method: 'upload_to_google_drive', + callback: function(r) { + frm.refresh(); + }, + freaze: true, + freaze_message: __("Uploading to Google Drive!") + }) + }, + view_in_gdrive: function(frm) { + window.open(frm.doc.google_drive_link); + } +}); diff --git a/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.json b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.json new file mode 100644 index 0000000..eb7fe5e --- /dev/null +++ b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.json @@ -0,0 +1,105 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "naming_series:", + "creation": "2023-11-21 13:17:49.581633", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "naming_series", + "parent_folder_name", + "file_folder_name", + "share_with", + "share_file_only", + "file", + "upload", + "google_drive_link", + "view_in_gdrive" + ], + "fields": [ + { + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 1, + "label": "Series", + "options": "GDU-.MM.-.YYYY.-.####" + }, + { + "fieldname": "parent_folder_name", + "fieldtype": "Data", + "label": "Parent Folder Name" + }, + { + "fieldname": "file_folder_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "File Folder Name", + "reqd": 1 + }, + { + "fieldname": "file", + "fieldtype": "Attach", + "in_list_view": 1, + "label": "File", + "reqd": 1 + }, + { + "depends_on": "eval:!doc.google_drive_link", + "fieldname": "upload", + "fieldtype": "Button", + "label": "Upload to Google Drive" + }, + { + "fieldname": "google_drive_link", + "fieldtype": "Data", + "label": "Google Drive Link", + "read_only": 1 + }, + { + "depends_on": "google_drive_link", + "fieldname": "view_in_gdrive", + "fieldtype": "Button", + "label": "View in Google Drive" + }, + { + "fieldname": "share_with", + "fieldtype": "Data", + "label": "Share With", + "options": "Email", + "reqd": 1 + }, + { + "default": "1", + "fieldname": "share_file_only", + "fieldtype": "Check", + "label": "Share File Only" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2023-11-27 08:59:31.556119", + "modified_by": "Administrator", + "module": "One Backup Manager", + "name": "GDrive Upload", + "naming_rule": "By \"Naming Series\" field", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.py b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.py new file mode 100644 index 0000000..b28e440 --- /dev/null +++ b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/gdrive_upload.py @@ -0,0 +1,102 @@ +# Copyright (c) 2023, ONE FM and contributors +# For license information, please see license.txt + +import frappe +from frappe.model.document import Document +from one_backup_manager.utils.gdrive import GoogleDriveUploader +import os +import datetime +from one_fm.api.api import upload_file as upload_file_to_db +from pathlib import Path +import hashlib +import base64 + +class GDriveUpload(Document): + @frappe.whitelist() + def upload_to_google_drive(self): + gdrive = GoogleDriveUploader() + file_path = os.getcwd()+"/"+frappe.utils.cstr(frappe.local.site)+'/private/files/' + file_name = frappe.db.get_value("File", {"file_url": self.file}, "file_name") + + parent_folder_ids = [] + + if self.parent_folder_name: + if self.share_file_only: + parent_folder = gdrive.create_folder(self.parent_folder_name) + else: + parent_folder = gdrive.create_folder(self.parent_folder_name, self.share_with) + parent_folder_ids.append(parent_folder.get('id')) + + if self.share_file_only: + file_folder = gdrive.create_folder(self.file_folder_name, parent_folder_ids) + else: + file_folder = gdrive.create_folder(self.file_folder_name, self.share_with, parent_folder_ids) + + try: + # Create file in google dirve + file = gdrive.upload_file(file_name, [file_folder.get('id')], file_path, self.share_with) + # Create Google Drive Log in our system with the google drive link to the file folder + gdrive.create_log(1, url=file.get('webViewLink')) + self.db_set("google_drive_link", file.get('webViewLink')) + frappe.msgprint("Upload to Google Drive Complete", alert =1) + except: + # Create error log and notifications if any exception happened in the google drive upload + frappe.log_error(message = frappe.get_traceback(),title="Error Uploading to Google Drive") + gdrive.notify(success= False, message = "

Please see error log from google drive upload


"+frappe.get_traceback()) + gdrive.create_log(0) + +@frappe.whitelist() +def upload_to_gdrive(file_name: str = None, file: str = None, gdrive_folder: str = None, share_with: str = None): + """[summary] + Args: + file_name (str): Name of the file + file (str): file + gdrive_folder (str): Google drive folder name + share_with (str): email id to share the file in google drive + Returns: + dict: { + message (str): Brief message indicating the response, + status_code (int): Status code of response. + data (str): The url to the file, + error (str): Any error handled. + } + """ + + if not file_name: + return response("Bad Request", 400, None, "file_name required.") + + if not file: + return response("Bad Request", 400, None, "file required.") + + if not gdrive_folder: + return response("Bad Request", 400, None, "gdrive_folder required.") + + if not share_with: + return response("Bad Request", 400, None, "share_with required.") + + if not isinstance(file_name, str): + return response("Bad Request", 400, None, "file_name must be of type str") + + if not isinstance(gdrive_folder, str): + return response("Bad Request", 400, None, "gdrive_folder must be of type str") + + try: + file_ext = "." + file_name.split(".")[-1] + content = base64.b64decode(file) + file_name = hashlib.md5((file_name + str(datetime.datetime.now())).encode('utf-8')).hexdigest() + file_ext + Path(frappe.utils.cstr(frappe.local.site)+f"/private/files/gdrive_upload").mkdir(parents=True, exist_ok=True) + file_path = frappe.utils.cstr(frappe.local.site)+f"/private/files/gdrive_upload/{filename}" + file_ = upload_file_to_db(doc, "attachments", filename, file_path, content, is_private=True) + + gdrive_upload = frappe.new_doc('GDrive Upload') + gdrive_upload.file_folder_name = gdrive_folder + gdrive_upload.share_with = share_with + gdrive_upload.share_file_only = True + gdrive_upload.file = file_.file_url + gdrive_upload.save(ignore_permissions=True) + gdrive_upload.upload_to_google_drive() + return response("Success", 201, gdrive_upload.google_drive_link) + + except Exception as error: + frappe.log_error(error, 'GDrive Upload API') + return response("Internal Server Error", 500, None, error) diff --git a/one_backup_manager/one_backup_manager/doctype/backup_log/test_backup_log.py b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/test_gdrive_upload.py similarity index 77% rename from one_backup_manager/one_backup_manager/doctype/backup_log/test_backup_log.py rename to one_backup_manager/one_backup_manager/doctype/gdrive_upload/test_gdrive_upload.py index fdb849e..45a4beb 100644 --- a/one_backup_manager/one_backup_manager/doctype/backup_log/test_backup_log.py +++ b/one_backup_manager/one_backup_manager/doctype/gdrive_upload/test_gdrive_upload.py @@ -5,5 +5,5 @@ from frappe.tests.utils import FrappeTestCase -class TestBackupLog(FrappeTestCase): +class TestGDriveUpload(FrappeTestCase): pass diff --git a/one_backup_manager/one_backup_manager/doctype/google_drive_log/__init__.py b/one_backup_manager/one_backup_manager/doctype/google_drive_log/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.js b/one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.js similarity index 77% rename from one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.js rename to one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.js index 391d4fb..147ce4b 100644 --- a/one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.js +++ b/one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.js @@ -1,7 +1,7 @@ // Copyright (c) 2023, ONE FM and contributors // For license information, please see license.txt -frappe.ui.form.on('Backup Log', { +frappe.ui.form.on('Google Drive Log', { // refresh: function(frm) { // } diff --git a/one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.json b/one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.json similarity index 98% rename from one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.json rename to one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.json index fa2532e..5a3f60a 100644 --- a/one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.json +++ b/one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.json @@ -69,7 +69,7 @@ "modified": "2023-10-15 17:49:33.678878", "modified_by": "Administrator", "module": "One Backup Manager", - "name": "Backup Log", + "name": "Google Drive Log", "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ diff --git a/one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.py b/one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.py similarity index 83% rename from one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.py rename to one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.py index 5d51378..53379c6 100644 --- a/one_backup_manager/one_backup_manager/doctype/backup_log/backup_log.py +++ b/one_backup_manager/one_backup_manager/doctype/google_drive_log/google_drive_log.py @@ -4,5 +4,5 @@ # import frappe from frappe.model.document import Document -class BackupLog(Document): +class GoogleDriveLog(Document): pass diff --git a/one_backup_manager/one_backup_manager/doctype/google_drive_log/test_google_drive_log.py b/one_backup_manager/one_backup_manager/doctype/google_drive_log/test_google_drive_log.py new file mode 100644 index 0000000..11f50dc --- /dev/null +++ b/one_backup_manager/one_backup_manager/doctype/google_drive_log/test_google_drive_log.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, ONE FM and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestGoogleDriveLog(FrappeTestCase): + pass diff --git a/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.js b/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.js index abe9198..0f34740 100644 --- a/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.js +++ b/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.js @@ -3,19 +3,38 @@ frappe.ui.form.on('One Backup Settings', { refresh: function(frm) { - frm.add_custom_button("Backup to Google Drive",function(){ - frappe.confirm("Are you sure you want to send the latest backup to Google Drive?",()=>{ - frappe.call({ - method:"one_backup_manager.one_backup_manager.doctype.one_backup_settings.one_backup_settings.create_backup", - callback:function(r){ - frappe.show_alert("Backup to Google Drive Initiated") - } - }) - }, - ()=>{ - ; - }) - - }) + if(frm.doc.enable_google_backups){ + frm.events.create_backup_button(frm) + } + }, + enable_google_backups: function(frm) { + if(!frm.doc.enable_google_backups){ + frm.set_value('enable_auto_backup_to_google_drive', false); + } + }, + create_backup_button: function(frm) { + frm.add_custom_button(__("Backup to Google Drive"), + function(){ + if(frm.is_dirty()){ + frappe.throw(__('Please Save the Document and Continue!')) + } + else{ + frappe.confirm( + "Are you sure you want to send the latest backup to Google Drive?", + ()=>{ + frappe.call({ + method:"one_backup_manager.one_backup_manager.doctype.one_backup_settings.one_backup_settings.create_backup", + callback:function(r){ + frappe.show_alert("Backup to Google Drive Initiated") + } + }); + }, + ()=>{ + // No + } + ); + } + } + ); } }); diff --git a/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.json b/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.json index 5f27c07..b63bc20 100644 --- a/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.json +++ b/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.json @@ -8,7 +8,7 @@ "engine": "InnoDB", "field_order": [ "enable_google_backups", - "google_json_credentials", + "enable_auto_backup_to_google_drive", "backup_folder_name", "column_break_yl6d0", "send_email_notifications_for_successful_backups", @@ -23,12 +23,6 @@ "fieldtype": "Check", "label": "Enable Google Backups" }, - { - "depends_on": "eval:doc.enable_google_backups", - "fieldname": "google_json_credentials", - "fieldtype": "Attach", - "label": "Google Json Credentials" - }, { "depends_on": "eval:doc.enable_google_backups", "description": "A custom name for the backup folder, If unset \"Backups\" will be used", @@ -38,10 +32,11 @@ }, { "default": "0", + "depends_on": "eval:doc.enable_google_backups", "description": "By default emails are only sent when a backup fails", "fieldname": "send_email_notifications_for_successful_backups", "fieldtype": "Check", - "label": "Send Email Notifications for Successful Backups" + "label": "Send Notifications for Successful Backups" }, { "depends_on": "eval:doc.enable_google_backups", @@ -54,6 +49,7 @@ }, { "default": "0", + "depends_on": "eval:doc.enable_google_backups", "description": "If Checked, the Public and Private files will also be uploaded to Drive", "fieldname": "backup_with_files", "fieldtype": "Check", @@ -64,15 +60,24 @@ "fieldtype": "Column Break" }, { + "depends_on": "eval:doc.enable_google_backups", "fieldname": "number_of_backups", "fieldtype": "Int", "label": "Number of Backups" + }, + { + "default": "0", + "depends_on": "enable_google_backups", + "description": "Check true for getting automatic backup daily to the google drive", + "fieldname": "enable_auto_backup_to_google_drive", + "fieldtype": "Check", + "label": "Enable Auto Backup to Google Drive" } ], "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-10-15 12:42:21.835555", + "modified": "2023-11-21 08:11:03.087217", "modified_by": "Administrator", "module": "One Backup Manager", "name": "One Backup Settings", diff --git a/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.py b/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.py index c3e2eef..a651cca 100644 --- a/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.py +++ b/one_backup_manager/one_backup_manager/doctype/one_backup_settings/one_backup_settings.py @@ -5,21 +5,85 @@ from frappe.model.document import Document from one_backup_manager.utils.gdrive import GoogleDriveUploader from frappe.utils.background_jobs import enqueue +from one_backup_manager.utils.utils import get_latest_backup_files +from frappe.utils import now class OneBackupSettings(Document): - pass + def validate(self): + if not self.enable_google_backups and self.enable_auto_backup_to_google_drive: + self.enable_auto_backup_to_google_drive = False + +@frappe.whitelist() +def auto_backup_to_gdrive(): + if frappe.db.get_single_value("One Backup Settings", "enable_auto_backup_to_google_drive"): + create_backup() + @frappe.whitelist() def create_backup(): """ - Starts the backup process in the background + Starts the backup process in the background """ - enqueue(method=new_backup,queue="long", - timeout=6000, event="Uploading Backups to Google Drive", - job_name="Uploading Backups to Google Drive", - now=False) + enqueue( + method=new_backup, + queue="long", + timeout=6000, + event="Uploading Backups to Google Drive", + job_name="Uploading Backups to Google Drive", + now=False + ) return True def new_backup(): - backup_doc = GoogleDriveUploader() - backup_doc.upload_file() - frappe.msgprint("Backup to Google Drive Complete",alert =1 ) \ No newline at end of file + ''' + Method to upload erp backup to google drive + ''' + # Check if enabled google backup + enable_google_backups = frappe.db.get_single_value("One Backup Settings", "enable_google_backups") + if enable_google_backups: + # Get latest backup files + backup_with_files = frappe.db.get_single_value("One Backup Settings", "backup_with_files") + # Get latset backup as a dict {'path': path to the file, 'files': list of name of the fiel with extension} + file_details = get_latest_backup_files(with_files = backup_with_files) + + files = file_details.get('files') + + # init backup file folder name + file_folder_name = '' + + if files and len(files) > 0: + # Set a backup file folder name + file_folder_name = files[0].split('-')[0] + else: + frappe.msgprint("No Backup files found to upload!", alert =1) + return False + + gdrive = GoogleDriveUploader() + parent_folder_ids = [] + + # Create parent folder in google drive and set permission for the folder if backup folder name is defined + if gdrive.settings_doc.backup_folder_name: + parent_folder = gdrive.create_folder(gdrive.settings_doc.backup_folder_name, gdrive.settings_doc.shared_email_address) + parent_folder_ids.append(parent_folder.get('id')) + + # Create folder for the backup in google drive and set permission for the folder + file_folder = gdrive.create_folder(file_folder_name, gdrive.settings_doc.shared_email_address, parent_folder_ids) + + # Iterate backup files and create the file in google drive + try: + for file in files: + # Create file in google dirve + file_upload = gdrive.upload_file(file, [file_folder.get('id')], file_details.get('path')) + # Create Google Drive Log in our system with the google drive link to the backup folder + gdrive.create_log(1, url=file_folder.get('webViewLink')) + + # Notify the backup google drive upload details + if gdrive.settings_doc.send_email_notifications_for_successful_backups: + backup_doc.notify(success = True,message = f"Please note that the backup of {frappe.local.site} is successful") + frappe.msgprint("Backup to Google Drive Complete", alert =1) + except: + # Create error log and notifications if any exception happened in the google drive upload + frappe.log_error(message = frappe.get_traceback(),title="Error Uploading to Google Drive") + gdrive.notify(success= False, message = "

Please see error log from google drive upload


"+frappe.get_traceback()) + gdrive.create_log(0) + else: + frappe.msgprint(_("Enable Google Backups in One Backup Settings")) diff --git a/one_backup_manager/utils/gdrive.py b/one_backup_manager/utils/gdrive.py index 4e1665e..7ee6ef9 100644 --- a/one_backup_manager/utils/gdrive.py +++ b/one_backup_manager/utils/gdrive.py @@ -1,127 +1,86 @@ import frappe from google.oauth2 import service_account import os,io +from frappe.utils.user import get_system_managers from datetime import datetime from frappe.utils import cstr -from one_fm.processor import sendemail from googleapiclient.discovery import build from googleapiclient import discovery from googleapiclient.http import MediaFileUpload -from one_backup_manager.utils.utils import get_latest_files class GoogleDriveUploader(): def __init__(self): self.settings_doc = frappe.get_doc("One Backup Settings") self.set_access_token() - if not self.settings_doc.google_json_credentials: - frappe.throw("Please set a credentials file in ONE Backup Settings") - + if not frappe.local.conf.google_service_account_credentials: + frappe.throw("Please set a credentials file in Site Config") + def set_access_token(self): - SERVICE_ACCOUNT_FILE = os.getcwd()+"/"+cstr(frappe.local.site) + self.settings_doc.google_json_credentials - + SERVICE_ACCOUNT_FILE = os.getcwd()+"/"+cstr(frappe.local.site) + frappe.local.conf.google_service_account_credentials + SCOPES = ["https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/drive"] self.credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES) self.service = discovery.build('sheets', 'v4', credentials=self.credentials) self.drive_api = build('drive', 'v3', credentials=self.credentials) - - - def notify(self,success = False,message = None): + + + def notify(self, success = False, message = None): """Notify users of the outcome of the backup process""" - recipient = self.settings_doc.shared_email_address + recipients = [self.settings_doc.shared_email_address] + recipients+= get_system_managers(only_name=1) + success_value = "Successful" if success else "Failed" - if not recipient: - recipient = frappe.conf.error_report_email - if not recipient: - frappe.throw("No Email Recipient Set") - sendemail(recipients=[recipient],subject = f"Backup {success_value}!",message = message ) - - def fetch_folder_id(self): - folder_name = self.settings_doc.backup_folder_name - if folder_name: - folder_exists = self.drive_api.files().list(q=f"name='{folder_name}'").execute()['files'] - if folder_exists: - folder = folder_exists[0] - else: - folder_metadata = { - "name": folder_name, - "mimeType": "application/vnd.google-apps.folder" - } - try: - folder = self.drive_api.files().create(body=folder_metadata, fields="id").execute() - permission = {'type': 'user','role': 'writer','emailAddress': self.settings_doc.shared_email_address} - self.drive_api.permissions().create(fileId=folder.get('id'), body=permission).execute() - except: - - frappe.log_error(message = frappe.get_traceback(),title="Error Creating Backup Folder") - return folder - - def validate_limit(self,parent_folder_id =None): - if not parent_folder_id: - parent_folder_id = self.fetch_folder_id() - if self.settings_doc.enable_google_backups: - limit = self.settings_doc.number_of_backups - if not limit: - limit = 3 - #list the folder in the root backup location - - sub_folders = self.drive_api.files().list(q=f"'{parent_folder_id.get('id')}' in parents and mimeType = 'application/vnd.google-apps.folder'",orderBy="createdTime desc").execute()['files'] - - if len(sub_folders) > (limit-1): - removed_folders = sub_folders[(limit-1):] - for folder in removed_folders: - self.drive_api.files().delete(fileId=folder['id']).execute() - + subject = f"Google drive upload {success_value}!" + + if recipients and len(recipients) > 0: + frappe.sendmail(recipients=recipients, subject=subject, message=message) def create_log(self,complete,url=None): """Create a Backup Log to reflect the status of the upload""" data = frappe._dict({ 'date':frappe.utils.getdate(), - 'doctype':'Backup Log', + 'doctype':'Google Drive Log', 'status':'Completed' if complete else "Failed" - }) + }) if not complete: data.error_message = frappe.get_traceback() log_doc = frappe.get_doc(data) if complete: log_doc.uploaded_files = self.settings_doc.backup_with_files log_doc.route = url - + log_doc.insert() frappe.db.commit() - - - def upload_file(self): - if not self.enable_google_backups: - return - files = get_latest_files(with_files = self.settings_doc.backup_with_files) - folder = self.fetch_folder_id() - first_file = files.get('files')[0] - file_folder_metadata = { - "name": first_file.split('-')[0], - "mimeType": "application/vnd.google-apps.folder", - "parents": [folder.get('id')] - } - self.validate_limit(parent_folder_id = folder) - filefolder = self.drive_api.files().create(body=file_folder_metadata, fields="id,webViewLink").execute() - permission = {'type': 'user','role': 'writer','emailAddress': self.settings_doc.shared_email_address} - self.drive_api.permissions().create(fileId=filefolder.get('id'), body=permission).execute() - if files: + + def create_folder(self, folder_name, share_with=False, parents=[]): + folder_exists = self.drive_api.files().list(q=f"name='{folder_name}'").execute()['files'] + if folder_exists: + folder = folder_exists[0] + else: + folder_metadata = { + "name": folder_name, + "mimeType": "application/vnd.google-apps.folder", + } + if parents and len(parents) > 0: + folder_metadata['parents'] = parents try: - for each in files.get('files'): - file_metadata = { - 'name': each, - "parents": [filefolder.get('id')] - } - media = MediaFileUpload(files.get('path')+each, resumable=True) - file_upload = self.drive_api.files().create(body=file_metadata, media_body=media, fields='id').execute() - - - self.create_log(1,url =filefolder.get('webViewLink')) - if self.settings_doc.send_email_notifications_for_successful_backups: - self.notify(success = True,message = f"Please note that the backup of {frappe.local.site} is successful") - - except: - - frappe.log_error(message = frappe.get_traceback(),title="Error Creating Backup") - self.notify(success= False,message = "

Please see error log from backup


"+frappe.get_traceback()) - self.create_log(0) \ No newline at end of file + folder = self.drive_api.files().create(body=folder_metadata, fields="id, webViewLink").execute() + self.create_permission(folder.get('id'), share_with) + except Exception as e: + frappe.log_error(message = frappe.get_traceback(),title="Error Creating Google Drive Folder") + return folder + + def upload_file(self, file_name_with_ext, parents, file_path, share_with=False): + file_metadata = { + 'name': file_name_with_ext, + "parents": parents + } + media = MediaFileUpload(file_path+file_name_with_ext, resumable=True) + file = self.drive_api.files().create(body=file_metadata, media_body=media, fields='id, webViewLink').execute() + self.create_permission(file.get('id'), share_with) + return file + + def create_permission(self, file_id, share_with): + if share_with: + permission = {'type': 'user','role': 'writer','emailAddress': share_with} + self.drive_api.permissions().create(fileId=file_id, body=permission).execute() diff --git a/one_backup_manager/utils/utils.py b/one_backup_manager/utils/utils.py index 48fd80c..3640eba 100644 --- a/one_backup_manager/utils/utils.py +++ b/one_backup_manager/utils/utils.py @@ -2,31 +2,20 @@ import os from frappe.utils.backups import fetch_latest_backups - - -def get_last_batch(): - return fetch_latest_backups() - - -def get_latest_files(with_files = 0): +def get_latest_backup_files(with_files = 0): """fetches the last created file based on frappe's naming culture""" try: files = [] - last_backup = get_last_batch() + last_backup = fetch_latest_backups() if not with_files: del last_backup['private'] del last_backup['public'] for each in last_backup: - #Pick the file name only + #Pick the file name with extension files.append(last_backup[each].split('/')[-1]) backup_location = os.getcwd()+"/"+frappe.utils.cstr(frappe.local.site)+'/private/backups/' - - return {"path":backup_location,'files':files} + + return {"path":backup_location, 'files':files} except: - frappe.throw('Error Fetch Latest Backup') + frappe.msgprint('Error Fetch Latest Backup') frappe.log_error(title = "Error Fetching Latest Backup files",message= frappe.get_traceback()) - - - - -