diff --git a/auto_database_backup/__manifest__.py b/auto_database_backup/__manifest__.py index 17e9f3ab4..abbdfd723 100755 --- a/auto_database_backup/__manifest__.py +++ b/auto_database_backup/__manifest__.py @@ -22,7 +22,7 @@ { 'name': "Automatic Database Backup To Local Server, Remote Server," "Google Drive, Dropbox, Onedrive, Nextcloud and Amazon S3 Odoo18", - 'version': '18.0.1.0.0', + 'version': '18.0.2.0.0', 'live_test_url': 'https://youtu.be/Q2yMZyYjuTI', 'category': 'Extra Tools', 'summary': 'Odoo Database Backup, Automatic Backup, Database Backup, Automatic Backup,Database auto-backup, odoo backup' diff --git a/auto_database_backup/data/ir_cron_data.xml b/auto_database_backup/data/ir_cron_data.xml index 906653dbe..428c11130 100755 --- a/auto_database_backup/data/ir_cron_data.xml +++ b/auto_database_backup/data/ir_cron_data.xml @@ -1,14 +1,33 @@ - - - Backup : Automatic Database Backup + + + Backup : Daily Database Backup code - model._schedule_auto_backup() + model._schedule_auto_backup('daily') 1 days + + + Backup : Weekly Database Backup + + code + model._schedule_auto_backup('weekly') + 1 + weeks + + + + Backup : Monthly Database Backup + + code + model._schedule_auto_backup('monthly') + 1 + months + + diff --git a/auto_database_backup/doc/RELEASE_NOTES.md b/auto_database_backup/doc/RELEASE_NOTES.md index b47cba69f..849167966 100755 --- a/auto_database_backup/doc/RELEASE_NOTES.md +++ b/auto_database_backup/doc/RELEASE_NOTES.md @@ -5,3 +5,9 @@ #### ADD - Initial commit for Automatic Database Backup To Local Server, Remote Server, Google Drive, Dropbox, Onedrive, Nextcloud and Amazon S3 Odoo18. + +#### 29.10.2024 +#### Version 18.0.2.0.0 +#### UPDT + +- Added feature to set Multi-Level Backup Storage, Store backups in multiple locations based on different intervals. diff --git a/auto_database_backup/models/db_backup_configure.py b/auto_database_backup/models/db_backup_configure.py index 5a7764dde..86f515b06 100755 --- a/auto_database_backup/models/db_backup_configure.py +++ b/auto_database_backup/models/db_backup_configure.py @@ -78,6 +78,11 @@ class DbBackupConfigure(models.Model): ('next_cloud', 'Next Cloud'), ('amazon_s3', 'Amazon S3') ], string='Backup Destination', help='Destination of the backup') + backup_frequency = fields.Selection([ + ('daily', 'Daily'), + ('weekly', 'Weekly'), + ('monthly', 'Monthly'), + ], default='daily', string='Backup Frequency', help='Frequency of Backup Scheduling') backup_path = fields.Char(string='Backup Path', help='Local storage directory path') sftp_host = fields.Char(string='SFTP Host', help='SFTP host details') @@ -215,8 +220,7 @@ class DbBackupConfigure(models.Model): ) response = s3_client.head_bucket(Bucket=self.bucket_file_name) if response['ResponseMetadata']['HTTPStatusCode'] == 200: - self.active = True - self.hide_active = True + self.active = self.hide_active = True return { 'type': 'ir.actions.client', 'tag': 'display_notification', @@ -232,8 +236,7 @@ class DbBackupConfigure(models.Model): _("Bucket not found. Please check the bucket name and" " try again.")) except Exception: - self.active = False - self.hide_active = False + self.active = self.hide_active = False return { 'type': 'ir.actions.client', 'tag': 'display_notification', @@ -255,11 +258,9 @@ class DbBackupConfigure(models.Model): ncx = NextCloud(self.domain, auth=HTTPBasicAuth(self.next_cloud_user_name, self.next_cloud_password)) - data = ncx.list_folders('/').__dict__ if data['raw'].status_code == 207: - self.active = True - self.hide_active = True + self.active = self.hide_active = True return { 'type': 'ir.actions.client', 'tag': 'display_notification', @@ -271,8 +272,7 @@ class DbBackupConfigure(models.Model): } } else: - self.active = False - self.hide_active = False + self.active = self.hide_active = False return { 'type': 'ir.actions.client', 'tag': 'display_notification', @@ -285,8 +285,7 @@ class DbBackupConfigure(models.Model): } } except Exception: - self.active = False - self.hide_active = False + self.active = self.hide_active = False return { 'type': 'ir.actions.client', 'tag': 'display_notification', @@ -303,10 +302,8 @@ class DbBackupConfigure(models.Model): def _compute_redirect_uri(self): """Compute the redirect URI for onedrive and Google Drive""" for rec in self: - base_url = request.env['ir.config_parameter'].get_param( - 'web.base.url') - rec.onedrive_redirect_uri = base_url + '/onedrive/authentication' - rec.gdrive_redirect_uri = base_url + '/google_drive/authentication' + rec.onedrive_redirect_uri = self.get_base_url() + '/onedrive/authentication' + rec.gdrive_redirect_uri = self.get_base_url() + '/google_drive/authentication' @api.depends('onedrive_access_token', 'onedrive_refresh_token') def _compute_is_onedrive_token_generated(self): @@ -340,57 +337,50 @@ class DbBackupConfigure(models.Model): } def action_get_onedrive_auth_code(self): - """Generate onedrive authorization code""" - AUTHORITY = \ - 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize' - action = self.env["ir.actions.act_window"].sudo()._for_xml_id( - "auto_database_backup.db_backup_configure_action") - base_url = request.env['ir.config_parameter'].get_param('web.base.url') - url_return = base_url + \ - '/web#id=%d&action=%d&view_type=form&model=%s' % ( - self.id, action['id'], 'db.backup.configure') + """Generate OneDrive authorization code.""" + AUTHORITY = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize' + base_url = self.get_base_url() + action_id = self.env["ir.actions.act_window"].sudo()._for_xml_id( + "auto_database_backup.db_backup_configure_action")['id'] + url_return = f"{base_url}/web#id={self.id}&action={action_id}&view_type=form&model=db.backup.configure" state = { 'backup_config_id': self.id, - 'url_return': url_return - } - encoded_params = urls.url_encode({ + 'url_return': url_return } + params = { 'response_type': 'code', 'client_id': self.onedrive_client_key, 'state': json.dumps(state), 'scope': ONEDRIVE_SCOPE, - 'redirect_uri': base_url + '/onedrive/authentication', + 'redirect_uri': f"{base_url}/onedrive/authentication", 'prompt': 'consent', 'access_type': 'offline' - }) - auth_url = "%s?%s" % (AUTHORITY, encoded_params) + } return { 'type': 'ir.actions.act_url', 'target': 'self', - 'url': auth_url, + 'url': f"{AUTHORITY}?{urls.url_encode(params)}", } def action_get_gdrive_auth_code(self): - """Generate google drive authorization code""" - action = self.env["ir.actions.act_window"].sudo()._for_xml_id( - "auto_database_backup.db_backup_configure_action") - base_url = request.env['ir.config_parameter'].get_param('web.base.url') - url_return = base_url + \ - '/web#id=%d&action=%d&view_type=form&model=%s' % ( - self.id, action['id'], 'db.backup.configure') + """Generate Google Drive authorization code.""" + GOOGLE_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/auth" + base_url = self.get_base_url() + action_id = self.env["ir.actions.act_window"].sudo()._for_xml_id( + "auto_database_backup.db_backup_configure_action")['id'] + url_return = f"{base_url}/web#id={self.id}&action={action_id}&view_type=form&model=db.backup.configure" state = { 'backup_config_id': self.id, - 'url_return': url_return - } - encoded_params = urls.url_encode({ + 'url_return': url_return } + params = { 'response_type': 'code', 'client_id': self.gdrive_client_key, 'scope': 'https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.file', - 'redirect_uri': base_url + '/google_drive/authentication', + 'redirect_uri': f"{base_url}/google_drive/authentication", 'access_type': 'offline', 'state': json.dumps(state), 'approval_prompt': 'force', - }) - auth_url = "%s?%s" % (GOOGLE_AUTH_ENDPOINT, encoded_params) + } + auth_url = f"{GOOGLE_AUTH_ENDPOINT}?{urls.url_encode(params)}" return { 'type': 'ir.actions.act_url', 'target': 'self', @@ -398,70 +388,64 @@ class DbBackupConfigure(models.Model): } def generate_onedrive_refresh_token(self): - """Generate onedrive access token from refresh token if expired""" - base_url = request.env['ir.config_parameter'].get_param('web.base.url') + """Generate OneDrive access token from refresh token if expired.""" + base_url = self.get_base_url() + token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" headers = {"Content-type": "application/x-www-form-urlencoded"} data = { 'client_id': self.onedrive_client_key, 'client_secret': self.onedrive_client_secret, 'scope': ONEDRIVE_SCOPE, 'grant_type': "refresh_token", - 'redirect_uri': base_url + '/onedrive/authentication', - 'refresh_token': self.onedrive_refresh_token + 'redirect_uri': f"{base_url}/onedrive/authentication", + 'refresh_token': self.onedrive_refresh_token, } try: - res = requests.post( - "https://login.microsoftonline.com/common/oauth2/v2.0/token", - data=data, headers=headers) + res = requests.post(token_url, data=data, headers=headers) res.raise_for_status() - response = res.content and res.json() or {} + response = res.json() if res.ok else {} if response: - expires_in = response.get('expires_in') + expires_in = response.get('expires_in', 0) self.write({ 'onedrive_access_token': response.get('access_token'), 'onedrive_refresh_token': response.get('refresh_token'), - 'onedrive_token_validity': fields.Datetime.now() + timedelta( - seconds=expires_in) if expires_in else False, + 'onedrive_token_validity': fields.Datetime.now() + timedelta(seconds=expires_in), }) except requests.HTTPError as error: - _logger.exception("Bad microsoft onedrive request : %s !", - error.response.content) + _logger.exception("Bad Microsoft OneDrive request: %s", error.response.content) raise error def get_onedrive_tokens(self, authorize_code): - """Generate onedrive tokens from authorization code.""" - headers = {"content-type": "application/x-www-form-urlencoded"} - base_url = request.env['ir.config_parameter'].get_param('web.base.url') + """Generate OneDrive tokens from authorization code.""" + headers = {"Content-Type": "application/x-www-form-urlencoded"} + base_url = self.get_base_url() data = { 'code': authorize_code, 'client_id': self.onedrive_client_key, 'client_secret': self.onedrive_client_secret, 'grant_type': 'authorization_code', 'scope': ONEDRIVE_SCOPE, - 'redirect_uri': base_url + '/onedrive/authentication' + 'redirect_uri': f"{base_url}/onedrive/authentication", } + token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" try: - res = requests.post( - "https://login.microsoftonline.com/common/oauth2/v2.0/token", - data=data, headers=headers) + res = requests.post(token_url, data=data, headers=headers) res.raise_for_status() - response = res.content and res.json() or {} + response = res.json() if res.ok else {} if response: - expires_in = response.get('expires_in') + expires_in = response.get('expires_in', 0) self.write({ 'onedrive_access_token': response.get('access_token'), 'onedrive_refresh_token': response.get('refresh_token'), - 'onedrive_token_validity': fields.Datetime.now() + timedelta( - seconds=expires_in) if expires_in else False, + 'onedrive_token_validity': fields.Datetime.now() + timedelta(seconds=expires_in), }) except requests.HTTPError as error: - _logger.exception("Bad microsoft onedrive request : %s !", - error.response.content) + _logger.exception("Bad Microsoft OneDrive request: %s", error.response.content) raise error def generate_gdrive_refresh_token(self): - """Generate Google Drive access token from refresh token if expired""" - headers = {"content-type": "application/x-www-form-urlencoded"} + """Generate Google Drive access token from refresh token if expired.""" + headers = {"Content-Type": "application/x-www-form-urlencoded"} data = { 'refresh_token': self.gdrive_refresh_token, 'client_id': self.gdrive_client_key, @@ -469,46 +453,44 @@ class DbBackupConfigure(models.Model): 'grant_type': 'refresh_token', } try: - res = requests.post(GOOGLE_TOKEN_ENDPOINT, data=data, - headers=headers) + res = requests.post(GOOGLE_TOKEN_ENDPOINT, data=data, headers=headers) res.raise_for_status() - response = res.content and res.json() or {} + response = res.json() if res.ok else {} if response: - expires_in = response.get('expires_in') + expires_in = response.get('expires_in', 0) self.write({ 'gdrive_access_token': response.get('access_token'), - 'gdrive_token_validity': fields.Datetime.now() + timedelta( - seconds=expires_in) if expires_in else False, + 'gdrive_token_validity': fields.Datetime.now() + timedelta(seconds=expires_in), }) except requests.HTTPError as error: - error_key = error.response.json().get("error", "nc") + error_key = error.response.json().get("error", "unknown error") error_msg = _( - "An error occurred while generating the token. Your" - "authorization code may be invalid or has already expired [%s]." - "You should check your Client ID and secret on the Google APIs" - " plateform or try to stop and restart your calendar" - " synchronisation.", - error_key) + "An error occurred while generating the token. Your " + "authorization code may be invalid or has already expired [%s]. " + "Please check your Client ID and secret on the Google APIs " + "platform or try stopping and restarting your calendar " + "synchronization.", + error_key + ) raise UserError(error_msg) def get_gdrive_tokens(self, authorize_code): - """Generate onedrive tokens from authorization code.""" + """Generate Google Drive tokens from authorization code.""" base_url = request.env['ir.config_parameter'].get_param('web.base.url') - headers = {"content-type": "application/x-www-form-urlencoded"} + headers = {"Content-Type": "application/x-www-form-urlencoded"} data = { 'code': authorize_code, 'client_id': self.gdrive_client_key, 'client_secret': self.gdrive_client_secret, 'grant_type': 'authorization_code', - 'redirect_uri': base_url + '/google_drive/authentication' + 'redirect_uri': f"{base_url}/google_drive/authentication", } try: - res = requests.post(GOOGLE_TOKEN_ENDPOINT, params=data, - headers=headers) + res = requests.post(GOOGLE_TOKEN_ENDPOINT, data=data, headers=headers) res.raise_for_status() - response = res.content and res.json() or {} + response = res.json() if res.ok else {} if response: - expires_in = response.get('expires_in') + expires_in = response.get('expires_in', 0) self.write({ 'gdrive_access_token': response.get('access_token'), 'gdrive_refresh_token': response.get('refresh_token'), @@ -517,8 +499,9 @@ class DbBackupConfigure(models.Model): }) except requests.HTTPError: error_msg = _( - "Something went wrong during your token generation. Maybe your" - " Authorization Code is invalid") + "Something went wrong during your token generation. " + "Your authorization code may be invalid." + ) raise UserError(error_msg) def get_dropbox_auth_url(self): @@ -573,8 +556,7 @@ class DbBackupConfigure(models.Model): ftp_server.quit() except Exception as e: raise UserError(_("FTP Exception: %s", e)) - self.hide_active = True - self.active = True + self.active = self.hide_active = True return { 'type': 'ir.actions.client', 'tag': 'display_notification', @@ -596,20 +578,18 @@ class DbBackupConfigure(models.Model): if self.backup_destination == 'local': self.hide_active = True - def _schedule_auto_backup(self): + def _schedule_auto_backup(self, frequency): """Function for generating and storing backup. Database backup for all the active records in backup configuration model will be created.""" - records = self.search([]) + records = self.search([('backup_frequency', '=', frequency)]) mail_template_success = self.env.ref( 'auto_database_backup.mail_template_data_db_backup_successful') mail_template_failed = self.env.ref( 'auto_database_backup.mail_template_data_db_backup_failed') for rec in records: - backup_time = fields.datetime.utcnow().strftime( - "%Y-%m-%d_%H-%M-%S") - backup_filename = "%s_%s.%s" % ( - rec.db_name, backup_time, rec.backup_format) + backup_time = fields.datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S") + backup_filename = f"{rec.db_name}_{backup_time}.{rec.backup_format}" rec.backup_filename = backup_filename # Local backup if rec.backup_destination == 'local': @@ -619,7 +599,7 @@ class DbBackupConfigure(models.Model): backup_file = os.path.join(rec.backup_path, backup_filename) f = open(backup_file, "wb") - self.dump_data(rec.db_name, f, rec.backup_format) + self.dump_data(rec.db_name, f, rec.backup_format, rec.backup_frequency) f.close() # Remove older backups if rec.auto_remove: @@ -631,8 +611,7 @@ class DbBackupConfigure(models.Model): if backup_duration.days >= rec.days_to_remove: os.remove(file) if rec.notify_user: - mail_template_success.send_mail(rec.id, - force_send=True) + mail_template_success.send_mail(rec.id, force_send=True) except Exception as e: rec.generated_exception = e _logger.info('FTP Exception: %s', e) @@ -654,7 +633,7 @@ class DbBackupConfigure(models.Model): ftp_server.cwd(rec.ftp_path) with open(temp.name, "wb+") as tmp: self.dump_data(rec.db_name, tmp, - rec.backup_format) + rec.backup_format, rec.backup_frequency) ftp_server.storbinary('STOR %s' % backup_filename, open(temp.name, "rb")) if rec.auto_remove: @@ -689,7 +668,7 @@ class DbBackupConfigure(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - self.dump_data(rec.db_name, tmp, rec.backup_format) + self.dump_data(rec.db_name, tmp, rec.backup_format, rec.backup_frequency) try: sftp.chdir(rec.sftp_path) except IOError as e: @@ -726,7 +705,7 @@ class DbBackupConfigure(models.Model): suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: self.dump_data(rec.db_name, tmp, - rec.backup_format) + rec.backup_format, rec.backup_frequency) try: headers = { "Authorization": "Bearer %s" % rec.gdrive_access_token} @@ -749,8 +728,7 @@ class DbBackupConfigure(models.Model): files_req = requests.get( "https://www.googleapis.com/drive/v3/files?q=%s" % query, headers=headers) - files = files_req.json()['files'] - for file in files: + for file in files_req.json()['files']: file_date_req = requests.get( "https://www.googleapis.com/drive/v3/files/%s?fields=createdTime" % file['id'], headers=headers) @@ -787,7 +765,7 @@ class DbBackupConfigure(models.Model): suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: self.dump_data(rec.db_name, tmp, - rec.backup_format) + rec.backup_format, rec.backup_frequency) try: dbx = dropbox.Dropbox( app_key=rec.dropbox_client_key, @@ -821,7 +799,7 @@ class DbBackupConfigure(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - self.dump_data(rec.db_name, tmp, rec.backup_format) + self.dump_data(rec.db_name, tmp, rec.backup_format, rec.backup_frequency) headers = { 'Authorization': 'Bearer %s' % rec.onedrive_access_token, 'Content-Type': 'application/json'} @@ -916,22 +894,22 @@ class DbBackupConfigure(models.Model): suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: self.dump_data(rec.db_name, tmp, - rec.backup_format) - backup_file_path = temp.name + rec.backup_format, rec.backup_frequency) + backup_file_name = temp.name remote_file_path = f"/{folder_name}/{rec.db_name}_" \ f"{backup_time}.{rec.backup_format}" - nc.put_file(remote_file_path, backup_file_path) + nc.put_file(remote_file_path, backup_file_name) else: # Dump the database to a temporary file temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: self.dump_data(rec.db_name, tmp, - rec.backup_format) - backup_file_path = temp.name + rec.backup_format, rec.backup_frequency) + backup_file_name = temp.name remote_file_path = f"/{folder_name}/{rec.db_name}_" \ f"{backup_time}.{rec.backup_format}" - nc.put_file(remote_file_path, backup_file_path) + nc.put_file(remote_file_path, backup_file_name) except Exception: raise ValidationError('Please check connection') # Amazon S3 Backup @@ -981,19 +959,19 @@ class DbBackupConfigure(models.Model): prefixes.add(prefix) # If the specified folder is present in the bucket, # take a backup of the database and upload it to the - # S3 bucket + # S3 bucket if rec.aws_folder_name in prefixes: temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: self.dump_data(rec.db_name, tmp, - rec.backup_format) - backup_file_path = temp.name + rec.backup_format, rec.backup_frequency) + backup_file_name = temp.name remote_file_path = f"{rec.aws_folder_name}/{rec.db_name}_" \ f"{backup_time}.{rec.backup_format}" s3.Object(rec.bucket_file_name, remote_file_path).upload_file( - backup_file_path) + backup_file_name) # If notify_user is enabled, send an email to the # user notifying them about the successful backup if rec.notify_user: @@ -1009,16 +987,14 @@ class DbBackupConfigure(models.Model): if rec.notify_user: mail_template_failed.send_mail(rec.id, force_send=True) - def dump_data(self, db_name, stream, backup_format): + def dump_data(self, db_name, stream, backup_format, backup_frequency): """Dump database `db` into file-like object `stream` if stream is None return a file object with the dump. """ - - cron_user_id = self.env.ref('auto_database_backup.ir_cron_auto_db_backup').user_id.id + cron_user_id = self.env.ref(f'auto_database_backup.ir_cron_auto_db_backup_{backup_frequency}').user_id.id if cron_user_id != self.env.user.id: _logger.error( 'Unauthorized database operation. Backups should only be available from the cron job.') raise ValidationError("Unauthorized database operation. Backups should only be available from the cron job.") - _logger.info('DUMP DB: %s format %s', db_name, backup_format) cmd = [find_pg_tool('pg_dump'), '--no-owner', db_name] env = exec_pg_environ() diff --git a/auto_database_backup/static/description/assets/modules/1.gif b/auto_database_backup/static/description/assets/modules/1.gif deleted file mode 100755 index ae3a880a2..000000000 Binary files a/auto_database_backup/static/description/assets/modules/1.gif and /dev/null differ diff --git a/auto_database_backup/static/description/assets/modules/1.jpg b/auto_database_backup/static/description/assets/modules/1.jpg new file mode 100644 index 000000000..3cb15fe01 Binary files /dev/null and b/auto_database_backup/static/description/assets/modules/1.jpg differ diff --git a/auto_database_backup/static/description/assets/modules/2.gif b/auto_database_backup/static/description/assets/modules/2.gif deleted file mode 100755 index d19e2b352..000000000 Binary files a/auto_database_backup/static/description/assets/modules/2.gif and /dev/null differ diff --git a/auto_database_backup/static/description/assets/modules/2.jpg b/auto_database_backup/static/description/assets/modules/2.jpg new file mode 100644 index 000000000..662cadcc3 Binary files /dev/null and b/auto_database_backup/static/description/assets/modules/2.jpg differ diff --git a/auto_database_backup/static/description/assets/modules/3.jpg b/auto_database_backup/static/description/assets/modules/3.jpg new file mode 100644 index 000000000..717a00443 Binary files /dev/null and b/auto_database_backup/static/description/assets/modules/3.jpg differ diff --git a/auto_database_backup/static/description/assets/modules/3.png b/auto_database_backup/static/description/assets/modules/3.png deleted file mode 100755 index 8513873ea..000000000 Binary files a/auto_database_backup/static/description/assets/modules/3.png and /dev/null differ diff --git a/auto_database_backup/static/description/assets/modules/4.png b/auto_database_backup/static/description/assets/modules/4.png old mode 100755 new mode 100644 index 3bedf7981..00ebf54ad Binary files a/auto_database_backup/static/description/assets/modules/4.png and b/auto_database_backup/static/description/assets/modules/4.png differ diff --git a/auto_database_backup/static/description/assets/modules/5.jpg b/auto_database_backup/static/description/assets/modules/5.jpg new file mode 100644 index 000000000..7c67e2eec Binary files /dev/null and b/auto_database_backup/static/description/assets/modules/5.jpg differ diff --git a/auto_database_backup/static/description/assets/modules/5.png b/auto_database_backup/static/description/assets/modules/5.png deleted file mode 100755 index 0e311ca87..000000000 Binary files a/auto_database_backup/static/description/assets/modules/5.png and /dev/null differ diff --git a/auto_database_backup/static/description/assets/modules/6.gif b/auto_database_backup/static/description/assets/modules/6.gif new file mode 100644 index 000000000..a35ece8df Binary files /dev/null and b/auto_database_backup/static/description/assets/modules/6.gif differ diff --git a/auto_database_backup/static/description/assets/modules/6.jpg b/auto_database_backup/static/description/assets/modules/6.jpg deleted file mode 100755 index 67c7f7062..000000000 Binary files a/auto_database_backup/static/description/assets/modules/6.jpg and /dev/null differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon10.png b/auto_database_backup/static/description/assets/screenshots/amazon10.png index 5e91106df..7fe959569 100644 Binary files a/auto_database_backup/static/description/assets/screenshots/amazon10.png and b/auto_database_backup/static/description/assets/screenshots/amazon10.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/backup_frequency.png b/auto_database_backup/static/description/assets/screenshots/backup_frequency.png new file mode 100644 index 000000000..3c9cd97e4 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/backup_frequency.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/drop4.png b/auto_database_backup/static/description/assets/screenshots/drop4.png old mode 100755 new mode 100644 index 20e0dde00..68900baa9 Binary files a/auto_database_backup/static/description/assets/screenshots/drop4.png and b/auto_database_backup/static/description/assets/screenshots/drop4.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/drop8.png b/auto_database_backup/static/description/assets/screenshots/drop8.png old mode 100755 new mode 100644 index 8fbbbf775..665779ef1 Binary files a/auto_database_backup/static/description/assets/screenshots/drop8.png and b/auto_database_backup/static/description/assets/screenshots/drop8.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/ftp.png b/auto_database_backup/static/description/assets/screenshots/ftp.png old mode 100755 new mode 100644 index 8d730f854..9ef05b303 Binary files a/auto_database_backup/static/description/assets/screenshots/ftp.png and b/auto_database_backup/static/description/assets/screenshots/ftp.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google 8.png b/auto_database_backup/static/description/assets/screenshots/google 8.png old mode 100755 new mode 100644 index c2dd5ea2d..e7ef0915b Binary files a/auto_database_backup/static/description/assets/screenshots/google 8.png and b/auto_database_backup/static/description/assets/screenshots/google 8.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google6.png b/auto_database_backup/static/description/assets/screenshots/google6.png old mode 100755 new mode 100644 index e0c684de8..ad04422c1 Binary files a/auto_database_backup/static/description/assets/screenshots/google6.png and b/auto_database_backup/static/description/assets/screenshots/google6.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google8.png b/auto_database_backup/static/description/assets/screenshots/google8.png new file mode 100644 index 000000000..487c8431b Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google8.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/img.png b/auto_database_backup/static/description/assets/screenshots/img.png new file mode 100644 index 000000000..1e925b284 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/img.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/img_1.png b/auto_database_backup/static/description/assets/screenshots/img_1.png new file mode 100644 index 000000000..1e925b284 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/img_1.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/img_2.png b/auto_database_backup/static/description/assets/screenshots/img_2.png new file mode 100644 index 000000000..e5d78bae7 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/img_2.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/local.png b/auto_database_backup/static/description/assets/screenshots/local.png old mode 100755 new mode 100644 index 12b3d80a6..dc1fac34a Binary files a/auto_database_backup/static/description/assets/screenshots/local.png and b/auto_database_backup/static/description/assets/screenshots/local.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/nextcloud1.png b/auto_database_backup/static/description/assets/screenshots/nextcloud1.png old mode 100755 new mode 100644 index 2f9855f3e..a57abaaa3 Binary files a/auto_database_backup/static/description/assets/screenshots/nextcloud1.png and b/auto_database_backup/static/description/assets/screenshots/nextcloud1.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/onedrive 4.png b/auto_database_backup/static/description/assets/screenshots/onedrive 4.png old mode 100755 new mode 100644 index 48e289310..af54f5c84 Binary files a/auto_database_backup/static/description/assets/screenshots/onedrive 4.png and b/auto_database_backup/static/description/assets/screenshots/onedrive 4.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/remove.png b/auto_database_backup/static/description/assets/screenshots/remove.png index 1f435f9ae..46d65cf56 100644 Binary files a/auto_database_backup/static/description/assets/screenshots/remove.png and b/auto_database_backup/static/description/assets/screenshots/remove.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/scheduled_action.png b/auto_database_backup/static/description/assets/screenshots/scheduled_action.png index 6a886eee0..d42c24ef6 100644 Binary files a/auto_database_backup/static/description/assets/screenshots/scheduled_action.png and b/auto_database_backup/static/description/assets/screenshots/scheduled_action.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/scheduled_action_form.png b/auto_database_backup/static/description/assets/screenshots/scheduled_action_form.png index 274a561ec..6da692e7c 100644 Binary files a/auto_database_backup/static/description/assets/screenshots/scheduled_action_form.png and b/auto_database_backup/static/description/assets/screenshots/scheduled_action_form.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/sftp.png b/auto_database_backup/static/description/assets/screenshots/sftp.png old mode 100755 new mode 100644 index 2cf9f727a..ce0b4d263 Binary files a/auto_database_backup/static/description/assets/screenshots/sftp.png and b/auto_database_backup/static/description/assets/screenshots/sftp.png differ diff --git a/auto_database_backup/static/description/index.html b/auto_database_backup/static/description/index.html index c3b59a69c..7a03ea94b 100644 --- a/auto_database_backup/static/description/index.html +++ b/auto_database_backup/static/description/index.html @@ -68,6 +68,9 @@ border-radius: 20px; width: 40px; height: 40px; + Reaso: irfan ooked me ver + + display: flex; justify-content: center; align-items: center; @@ -325,9 +328,7 @@
+ style="border-radius: 12px; border: 1px solid #B6BCCD; background: #FFF;padding:32px;">
+
+
+
+ +
+
+ Multi-Level Backup Storage +
+

+ Store backups in multiple locations based on different intervals.

+
+
-
+
Automatic Database Backup @@ -516,6 +538,36 @@

+ Backup + Frequency +

+
+
+

+ Specify Backup + Destination and Frequency. Choose how often the backup should + run: daily, weekly, or monthly. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

Store Backup to Remote @@ -592,7 +644,12 @@

- You'll need to create a new Google API project from Google Cloud console and enabling the Google Drive API, Go to the Google API Console and log into your account. While creating the project, for the Redirect URI restrictions, copy your Odoo database URI followed by /google_drive/authentication. Example: + You'll need to create a new Google API project from Google Cloud console + and enabling the Google Drive API, Go to the Google API Console and log + into your account. While creating the project, for the Redirect URI + restrictions, copy your Odoo database URI followed by + /google_drive/authentication. Example:

@@ -634,7 +691,8 @@

- Create Credentials, Follow the steps, select Website application for the Application Type. + Create Credentials, Follow the steps, select Website application for the + Application Type.

@@ -648,7 +706,12 @@

- Under the Authorized JavaScript Origins section, click + Add URI and type your company's Odoo URL address. Under the Authorized redirect URIs section, click + Add URI and type your company's Odoo URL address followed by /google_drive/authentication. After all the steps are completed, A Client ID and Client secret will be given, copy the credentials + Under the Authorized JavaScript Origins section, click + Add URI and + type your company's Odoo URL address. Under the Authorized redirect URIs + section, click + Add URI and type your company's Odoo URL address + followed by /google_drive/authentication. After all the steps are + completed, A Client ID and Client secret will be given, copy the + credentials

@@ -662,7 +725,9 @@

- Configure Backup, Copy Client ID and Client Secret from Google Drive API Credentials page into their respective fields. Setup Token will redirect to an authorization page. + Configure Backup, Copy Client ID and Client Secret from Google Drive API + Credentials page into their respective fields. Setup Token will redirect + to an authorization page.

@@ -720,7 +785,9 @@

- To get the app key and secret key go to the App Console . Create a new app + To get the app key and secret key go to the App Console . Create a + new app

@@ -734,7 +801,8 @@

- Once you created the App , you can get the App key and App Secret as seen in the screenshot. + Once you created the App , you can get the App key and App Secret as + seen in the screenshot.

@@ -748,7 +816,8 @@

- Choose your app's permission (files.content.write and files.content.read permissions required).then click on Submit + Choose your app's permission (files.content.write and files.content.read + permissions required).then click on Submit

@@ -762,7 +831,8 @@

- Choose Dropbox as that of the backup destination. Enter the app secret and key and dropbox Folder. Click on the Setup Token + Choose Dropbox as that of the backup destination. Enter the app secret + and key and dropbox Folder. Click on the Setup Token

@@ -790,7 +860,7 @@

- Reset the refresh token if required by clicking on the "Reset Token" + Reset the refresh token if required by clicking on the "Reset Token"

@@ -820,7 +890,11 @@

- Select Backup Destination as OneDrive. Enter the App key and App secret. you'll need to register a new app in the Microsoft Azure portal. While registering the app for the Redirect URI restrictions, copy your Odoo database URI followed by /onedrive/authentication. Example: + Select Backup Destination as OneDrive. + Enter the App key and App secret. you'll need to register a new app in + the Microsoft Azure portal. While registering the app for the Redirect + URI restrictions, copy your Odoo database URI followed by + /onedrive/authentication. Example:

@@ -834,7 +908,7 @@

- Copy the Client ID and Generate Client Secret. + Copy the Client ID and Generate Client Secret.

@@ -931,7 +1005,8 @@

- To Create an account in Nextcloud go to https://nextcloud.com/sign-up/, Enter Your Email Address and Sign up . + To Create an account in Nextcloud go to https://nextcloud.com/sign-up/, + Enter Your Email Address and Sign up .

@@ -945,7 +1020,8 @@

- You will be redirected to the page as shown in the screenshot, and it will ask you enter your email and password for the Nextcloud. + You will be redirected to the page as shown in the screenshot, and it + will ask you enter your email and password for the Nextcloud.

@@ -959,7 +1035,9 @@

- To get the Domain of the Nextcloud.Go to Settings in the Nextcloud and Click on Mobile & desktop. You will see server address Copy link and paste it in your Domain Name. + To get the Domain of the Nextcloud.Go to Settings in the Nextcloud and + Click on Mobile & desktop. You will see server address Copy link and + paste it in your Domain Name.

@@ -973,7 +1051,10 @@

- Select the backup destination as Nextcloud. Enter the Domain Name, UserName, Password and Folder Name where you want to store your backup on the NextCloud server. Check the Connect button to check if the connection is successful. + Select the backup destination as Nextcloud. Enter the Domain Name, + UserName, Password and Folder Name where you want to store your backup + on the NextCloud server. Check the Connect button to check if the + connection is successful.

@@ -987,7 +1068,9 @@

- Every day, a Scheduled Action will take place to store a backup on the Nextcloud Server. The backup will be stored as the folder name provided in the Folder ID field in Odoo. + Every day, a Scheduled Action will take place to store a backup on the + Nextcloud Server. The backup will be stored as the folder name provided + in the Folder ID field in Odoo.

@@ -1017,7 +1100,9 @@

- To Create an account in Amazon S3 go to https://portal.aws.amazon.com/billing/signup#/start/email, Enter Your Email Address and Sign up . + To Create an account in Amazon S3 go to + https://portal.aws.amazon.com/billing/signup#/start/email, Enter Your + Email Address and Sign up .

@@ -1031,7 +1116,10 @@

- After you created the account.You need to get the Access Key and Secret Key,To get these go the account Security credentails and go the Access Keys and create new access keys from there you will get Access Key and Secret Key.

+ After you created the account.You need to get the Access Key and Secret + Key,To get these go the account Security credentails and go the Access + Keys and create new access keys from there you will get Access Key and + Secret Key.

- Next You need to create a Bucket Folder in the Amazon S3.To do that Go the Services in the top right and go to Storage and S3 as shown in the Screen shot. + Next You need to create a Bucket Folder in the Amazon S3.To do that Go + the Services in the top right and go to Storage and S3 as shown in the + Screen shot.

- To create Bucket folder,Click on the Create bucket Button. + To create Bucket folder,Click on the Create bucket Button.

- On Creating a Bucket Folder,Check the rules for naming the Bucket folder,and Select the region as well.After that click on the create Bucket Button in the bottom of the page. + On Creating a Bucket Folder,Check the rules for naming the Bucket + folder,and Select the region as well.After that click on the create + Bucket Button in the bottom of the page.

- You will see the Bucket Folder as shown in the screenshot. + You will see the Bucket Folder as shown in the screenshot.

- Select Backup Destination as Amazon S3. Enter the Amazon S3 Access Key,Amazon S3 Secret Key,Bucket Name->Bucket folder you have created in the Amazon S3 and the File Name->The Folder You want to store your backup in Amazon S3 Bucket Folder.Test connection button to check whether the connection is successful. + Select Backup Destination as Amazon S3. Enter the Amazon S3 Access + Key,Amazon S3 Secret Key,Bucket Name->Bucket folder you have created in + the Amazon S3 and the File Name->The Folder You want to store your + backup in Amazon S3 Bucket Folder.Test connection button to check + whether the connection is successful.

- Every day, a Scheduled Action will take place to store a backup on the Amazon S3 Server. The backup will be stored as the folder name provided in the File Name field in Odoo.

+ Every day, a Scheduled Action will take place to store a backup on the + Amazon S3 Server. The backup will be stored as the folder name provided + in the File Name field in Odoo.
@@ -1189,7 +1287,9 @@

- Enable notify user option, and select a user to notify. An email notification will be sent to the selected user on backup successful and failure. + Enable notify user option, and select a user to notify. An email + notification will be sent to the selected user on backup successful and + failure.

@@ -1267,14 +1367,16 @@

- Scheduled Action For + Scheduled Actions For Generating Backup.

- Enable the 'Automatic database Backup' scheduled action, and set up the execution interval. Based on the scheduled action setup, backups will be generated on regular intervals. + Enable the 'Automatic Database Backup' for the three scheduled actions. + Based on the setup, backups will be generated at daily, weekly, and + monthly intervals.

@@ -1304,7 +1406,6 @@
-
+
- - db.backup.configure.view.tree + + db.backup.configure.view.list db.backup.configure + @@ -36,6 +37,7 @@ + diff --git a/auto_database_backup/wizard/dropbox_auth_code.py b/auto_database_backup/wizard/dropbox_auth_code.py index 791be92cf..b28697714 100755 --- a/auto_database_backup/wizard/dropbox_auth_code.py +++ b/auto_database_backup/wizard/dropbox_auth_code.py @@ -54,6 +54,5 @@ class AuthenticationWizard(models.TransientModel): provided authorization code.""" backup_config = self.env['db.backup.configure'].browse( self.env.context.get('active_id')) - backup_config.hide_active = True - backup_config.active = True + backup_config.active = backup_config.hide_active= True backup_config.set_dropbox_refresh_token(self.dropbox_authorization_code)