diff --git a/auto_database_backup/README.rst b/auto_database_backup/README.rst new file mode 100755 index 000000000..d7eb8309b --- /dev/null +++ b/auto_database_backup/README.rst @@ -0,0 +1,52 @@ +.. image:: https://img.shields.io/badge/licence-LGPL--3-green.svg + :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +Automatic Database Backup To Local Server, Remote Server, Google Drive, Dropbox, Onedrive, Nextcloud and Amazon S3 +================================================================================================================== +* Generate Database Backups and store to multiple locations + +Configuration +============ +- www.odoo.com/documentation/18.0/setup/install.html +- Install our custom addon + +License +------- +General Public License, Version 3 (LGPL v3). +(https://www.gnu.org/licenses/lgpl-3.0-standalone.html) + +Company +------- +* `Cybrosys Techno Solutions `__ + +Credits +------- +* Developers : (v15) Midilaj, + (v16) Midilaj, + (v16 Amazon S3,NextCloud) Anfas Faisal K, + (v17) Aslam A K, + (v18) Aslam A K, + (v19) Ashwin A + Contact : odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ \ No newline at end of file diff --git a/auto_database_backup/__init__.py b/auto_database_backup/__init__.py new file mode 100755 index 000000000..9d4f012fa --- /dev/null +++ b/auto_database_backup/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import controllers +from . import models +from . import wizard diff --git a/auto_database_backup/__manifest__.py b/auto_database_backup/__manifest__.py new file mode 100755 index 000000000..e82385fa4 --- /dev/null +++ b/auto_database_backup/__manifest__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +{ + 'name': "Automatic Database Backup To Local Server, Remote Server," + "Google Drive, Dropbox, Onedrive, Nextcloud and Amazon S3 Odoo19", + 'version': '19.0.1.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' + 'google drive, dropbox, nextcloud, amazon S3, onedrive or ' + 'remote server, Odoo19, Backup, Database, Odoo Apps', + 'description': 'Odoo Database Backup, Database Backup, Automatic Backup, automatic database backup, odoo19, odoo apps,backup, automatic backup,odoo19 automatic database backup,backup google drive,backup dropbox, backup nextcloud, backup amazon S3, backup onedrive', + 'author': "Cybrosys Techno Solutions", + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'mail'], + 'data': [ + 'security/ir.model.access.csv', + 'data/ir_cron_data.xml', + 'data/mail_template_data.xml', + 'views/db_backup_configure_views.xml', + 'wizard/dropbox_auth_code_views.xml', + ], + 'external_dependencies': { + 'python': ['dropbox', 'pyncclient', 'boto3', 'nextcloud-api-wrapper','paramiko']}, + 'images': ['static/description/banner.gif'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/auto_database_backup/controllers/__init__.py b/auto_database_backup/controllers/__init__.py new file mode 100755 index 000000000..37abb9675 --- /dev/null +++ b/auto_database_backup/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import auto_database_backup diff --git a/auto_database_backup/controllers/auto_database_backup.py b/auto_database_backup/controllers/auto_database_backup.py new file mode 100755 index 000000000..c94de76e5 --- /dev/null +++ b/auto_database_backup/controllers/auto_database_backup.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +import json +from odoo import http +from odoo.http import request + + +class OnedriveAuth(http.Controller): + """Controller for handling authentication with OneDrive and Google Drive.""" + @http.route('/onedrive/authentication', type='http', auth="public") + def oauth2callback(self, **kw): + """ + Callback function for OneDrive authentication. + :param kw: A dictionary of keyword arguments. + :return: A redirect response. + """ + state = json.loads(kw['state']) + backup_config = request.env['db.backup.configure'].sudo().browse( + state.get('backup_config_id')) + backup_config.get_onedrive_tokens(kw.get('code')) + backup_config.hide_active = True + backup_config.active = True + return request.redirect(state.get('url_return')) + + @http.route('/google_drive/authentication', type='http', auth="public") + def gdrive_oauth2callback(self, **kw): + """Callback function for Google Drive authentication.""" + state = json.loads(kw['state']) + backup_config = request.env['db.backup.configure'].sudo().browse( + state.get('backup_config_id')) + backup_config.get_gdrive_tokens(kw.get('code')) + backup_config.hide_active = True + backup_config.active = True + return request.redirect(state.get('url_return')) diff --git a/auto_database_backup/data/ir_cron_data.xml b/auto_database_backup/data/ir_cron_data.xml new file mode 100755 index 000000000..428c11130 --- /dev/null +++ b/auto_database_backup/data/ir_cron_data.xml @@ -0,0 +1,33 @@ + + + + + + Backup : Daily Database Backup + + code + 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/data/mail_template_data.xml b/auto_database_backup/data/mail_template_data.xml new file mode 100755 index 000000000..9568d9932 --- /dev/null +++ b/auto_database_backup/data/mail_template_data.xml @@ -0,0 +1,194 @@ + + + + + + Database Backup: Notification Successful + + Database Backup Successful: {{ object.db_name }} + {{ object.user_id.email_formatted }} + + +
+

+ Dear , + +
+
+ Backup of the database + + + + has been successfully generated and stored to + + Local + + + Google Drive + + + FTP Server + + + SFTP Server + + + Dropbox + + + Onedrive + + + NextCloud + + + Amazon S3 + + . +
+
+ Database Name: + +
+ Destination: + + Local + + + Google Drive + + + FTP Server + + + SFTP Server + + + Dropbox + + + Onedrive + + + NextCloud + + + Amazon S3 + + +
+ Backup Path: + + + + + + + + + + + + + + + + + + + +
+ Backup Type: + +
+ Backup FileName: + +
+

+
+
+
+ + + Database Backup: Notification Failed + + Database Backup Failed: {{ object.db_name }} + {{ object.user_id.email_formatted }} + + +
+

+ Dear , + +
+
+ Backup generation of the database + + + + has been Failed. +
+
+ Database Name: +
+ Destination: + + Local + + + Google Drive + + + FTP Server + + + SFTP Server + + + Dropbox + + + Onedrive + + + NextCloud + + + Amazon S3 + + +
+ Backup Path: + + + + + + + + + + + + + + + + + + + +
+ Backup Type: +
+
+ Error Message: +
+ +
+

+
+
+
+
+
diff --git a/auto_database_backup/doc/RELEASE_NOTES.md b/auto_database_backup/doc/RELEASE_NOTES.md new file mode 100755 index 000000000..ce4360e43 --- /dev/null +++ b/auto_database_backup/doc/RELEASE_NOTES.md @@ -0,0 +1,7 @@ +## Module + +#### 19.09.2025 +#### Version 19.0.1.0.0 +#### ADD + +- Initial commit for Automatic Database Backup To Local Server, Remote Server, Google Drive, Dropbox, Onedrive, Nextcloud and Amazon S3 Odoo19. diff --git a/auto_database_backup/models/__init__.py b/auto_database_backup/models/__init__.py new file mode 100755 index 000000000..f550c8d05 --- /dev/null +++ b/auto_database_backup/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import db_backup_configure diff --git a/auto_database_backup/models/db_backup_configure.py b/auto_database_backup/models/db_backup_configure.py new file mode 100755 index 000000000..3ba4150f0 --- /dev/null +++ b/auto_database_backup/models/db_backup_configure.py @@ -0,0 +1,1092 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from email.policy import default + +import boto3 +import dropbox +import errno +import ftplib +import json +import logging +import nextcloud_client +import os +import paramiko +import requests +import shutil +import subprocess +import tempfile +import odoo +from datetime import datetime, timedelta +from nextcloud import NextCloud +from requests.auth import HTTPBasicAuth +from werkzeug import urls +from odoo import api, fields, models, _ +from odoo.exceptions import UserError, ValidationError +from odoo.tools.misc import find_pg_tool, exec_pg_environ +from odoo.http import request +from odoo.service import db + +_logger = logging.getLogger(__name__) +ONEDRIVE_SCOPE = ['offline_access openid Files.ReadWrite.All'] +MICROSOFT_GRAPH_END_POINT = "https://graph.microsoft.com" +GOOGLE_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth' +GOOGLE_TOKEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token' +GOOGLE_API_BASE_URL = 'https://www.googleapis.com' + + +class DbBackupConfigure(models.Model): + """DbBackupConfigure class provides an interface to manage database + backups of Local Server, Remote Server, Google Drive, Dropbox, Onedrive, + Nextcloud and Amazon S3""" + _name = 'db.backup.configure' + _description = 'Automatic Database Backup' + + name = fields.Char(string='Name', required=True, help='Add the name') + db_name = fields.Char(string='Database Name', required=True, + help='Name of the database') + master_pwd = fields.Char(string='Master Password', required=True, + help='Master password') + backup_format = fields.Selection([ + ('zip', 'Zip'), + ('dump', 'Dump') + ], string='Backup Format', default='zip', required=True, + help='Format of the backup') + backup_destination = fields.Selection([ + ('local', 'Local Storage'), + ('google_drive', 'Google Drive'), + ('ftp', 'FTP'), + ('sftp', 'SFTP'), + ('dropbox', 'Dropbox'), + ('onedrive', 'Onedrive'), + ('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') + sftp_port = fields.Char(string='SFTP Port', default=22, + help='SFTP port details') + sftp_user = fields.Char(string='SFTP User', copy=False, + help='SFTP user details') + sftp_password = fields.Char(string='SFTP Password', copy=False, + help='SFTP password') + sftp_path = fields.Char(string='SFTP Path', help='SFTP path details') + ftp_host = fields.Char(string='FTP Host', help='FTP host details') + ftp_port = fields.Char(string='FTP Port', default=21, + help='FTP port details') + ftp_user = fields.Char(string='FTP User', copy=False, + help='FTP user details') + ftp_password = fields.Char(string='FTP Password', copy=False, + help='FTP password') + ftp_path = fields.Char(string='FTP Path', help='FTP path details') + dropbox_client_key = fields.Char(string='Dropbox Client ID', copy=False, + help='Client id of the dropbox') + dropbox_client_secret = fields.Char(string='Dropbox Client Secret', + copy=False, + help='Client secret id of the dropbox') + dropbox_refresh_token = fields.Char(string='Dropbox Refresh Token', + copy=False, + help='Refresh token for the dropbox') + is_dropbox_token_generated = fields.Boolean( + string='Dropbox Token Generated', + compute='_compute_is_dropbox_token_generated', + copy=False, help='Is the dropbox token generated or not?') + dropbox_folder = fields.Char(string='Dropbox Folder', + help='Dropbox folder') + active = fields.Boolean(default=False, string='Active', + help='Activate the Scheduled Action or not') + hide_active = fields.Boolean(string="Hide Active", + help="Make active field to readonly") + auto_remove = fields.Boolean(string='Remove Old Backups', + help='Remove old backups') + days_to_remove = fields.Integer(string='Remove After', + default=1, + help='Automatically delete stored backups' + ' after this specified number of days') + google_drive_folder_key = fields.Char(string='Drive Folder ID', + help='Folder id of the drive') + notify_user = fields.Boolean(string='Notify User', + help='Send an email notification to user when' + 'the backup operation is successful' + ' or failed') + user_id = fields.Many2one('res.users', string='User', + help='Name of the user') + backup_filename = fields.Char(string='Backup Filename', + help='For Storing generated backup filename') + generated_exception = fields.Char(string='Exception', + help='Exception Encountered while Backup ' + 'generation') + onedrive_client_key = fields.Char(string='Onedrive Client ID', copy=False, + help='Client ID of the onedrive') + onedrive_client_secret = fields.Char(string='Onedrive Client Secret', + copy=False, help='Client secret id of' + ' the onedrive') + onedrive_access_token = fields.Char(string='Onedrive Access Token', + copy=False, + help='Access token for one drive') + onedrive_refresh_token = fields.Char(string='Onedrive Refresh Token', + copy=False, + help='Refresh token for one drive') + onedrive_token_validity = fields.Datetime(string='Onedrive Token Validity', + copy=False, + help='Token validity date') + onedrive_folder_key = fields.Char(string='Folder ID', + help='Folder id of the onedrive') + is_onedrive_token_generated = fields.Boolean( + string='onedrive Tokens Generated', + compute='_compute_is_onedrive_token_generated', + copy=False, help='Whether to generate onedrive token?') + gdrive_refresh_token = fields.Char(string='Google drive Refresh Token', + copy=False, + help='Refresh token for google drive') + gdrive_access_token = fields.Char(string='Google Drive Access Token', + copy=False, + help='Access token for google drive') + is_google_drive_token_generated = fields.Boolean( + string='Google drive Token Generated', + compute='_compute_is_google_drive_token_generated', copy=False, + help='Google drive token generated or not') + gdrive_client_key = fields.Char(string='Google Drive Client ID', + copy=False, + help='Client id of the google drive') + gdrive_client_secret = fields.Char(string='Google Drive Client Secret', + copy=False, + help='Client secret id of the google' + ' drive') + gdrive_token_validity = fields.Datetime( + string='Google Drive Token Validity', copy=False, + help='Token validity of the google drive') + onedrive_redirect_uri = fields.Char(string='Onedrive Redirect URI', + compute='_compute_redirect_uri', + help='Redirect URI of the onedrive') + gdrive_redirect_uri = fields.Char(string='Google Drive Redirect URI', + compute='_compute_redirect_uri', + help='Redirect URI of the google drive') + domain = fields.Char(string='Domain Name', help="Field used to store the " + "name of a domain") + next_cloud_user_name = fields.Char(string='User Name', + help="Field used to store the user name" + " for a Nextcloud account.") + next_cloud_password = fields.Char(string='Password', + help="Field used to store the password" + " for a Nextcloud account.") + nextcloud_folder_key = fields.Char(string='Next Cloud Folder Id', + help="Field used to store the unique " + "identifier for a Nextcloud " + "folder.") + aws_access_key = fields.Char(string="Amazon S3 Access Key", + help="Field used to store the Access Key" + " for an Amazon S3 bucket.") + aws_secret_access_key = fields.Char(string='Amazon S3 Secret Key', + help="Field used to store the Secret" + " Key for an Amazon S3 bucket.") + bucket_file_name = fields.Char(string='Bucket Name', + help="Field used to store the name of an" + " Amazon S3 bucket.") + aws_folder_name = fields.Char(string='File Name', + help="field used to store the name of a" + " folder in an Amazon S3 bucket.") + + def action_s3cloud(self): + """If it has aws_secret_access_key, which will perform s3cloud + operations for connection test""" + if self.aws_access_key and self.aws_secret_access_key: + try: + s3_client = boto3.client( + 's3', + aws_access_key_id=self.aws_access_key, + aws_secret_access_key=self.aws_secret_access_key + ) + response = s3_client.head_bucket(Bucket=self.bucket_file_name) + if response['ResponseMetadata']['HTTPStatusCode'] == 200: + self.active = self.hide_active = True + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'title': _("Connection Test Succeeded!"), + 'message': _( + "Everything seems properly set up!"), + 'sticky': False, + } + } + raise UserError( + _("Bucket not found. Please check the bucket name and" + " try again.")) + except Exception: + self.active = self.hide_active = False + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'danger', + 'title': _("Connection Test Failed!"), + 'message': _("An error occurred while testing the " + "connection."), + 'sticky': False, + } + } + + def action_nextcloud(self): + """If it has next_cloud_password, domain, and next_cloud_user_name + which will perform an action for nextcloud connection test""" + if self.domain and self.next_cloud_password and \ + self.next_cloud_user_name: + try: + 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 = self.hide_active = True + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'title': _("Connection Test Succeeded!"), + 'message': _("Everything seems properly set up!"), + 'sticky': False, + } + } + else: + self.active = self.hide_active = False + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'danger', + 'title': _("Connection Test Failed!"), + 'message': _("An error occurred while testing the " + "connection."), + 'sticky': False, + } + } + except Exception: + self.active = self.hide_active = False + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'danger', + 'title': _("Connection Test Failed!"), + 'message': _("An error occurred while testing the " + "connection."), + 'sticky': False, + } + } + + @api.depends('onedrive_redirect_uri', 'gdrive_redirect_uri') + def _compute_redirect_uri(self): + """Compute the redirect URI for onedrive and Google Drive""" + for rec in self: + 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): + """Set true if onedrive tokens are generated""" + for rec in self: + rec.is_onedrive_token_generated = bool( + rec.onedrive_access_token) and bool(rec.onedrive_refresh_token) + + @api.depends('dropbox_refresh_token') + def _compute_is_dropbox_token_generated(self): + """Set True if the dropbox refresh token is generated""" + for rec in self: + rec.is_dropbox_token_generated = bool(rec.dropbox_refresh_token) + + @api.depends('gdrive_access_token', 'gdrive_refresh_token') + def _compute_is_google_drive_token_generated(self): + """Set True if the Google Drive refresh token is generated""" + for rec in self: + rec.is_google_drive_token_generated = bool( + rec.gdrive_access_token) and bool(rec.gdrive_refresh_token) + + def action_get_dropbox_auth_code(self): + """Open a wizards to set up dropbox Authorization code""" + return { + 'type': 'ir.actions.act_window', + 'name': 'Dropbox Authorization Wizard', + 'res_model': 'dropbox.auth.code', + 'view_mode': 'form', + 'target': 'new', + 'context': {'dropbox_auth': True} + } + + def action_get_onedrive_auth_code(self): + """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} + params = { + 'response_type': 'code', + 'client_id': self.onedrive_client_key, + 'state': json.dumps(state), + 'scope': ONEDRIVE_SCOPE, + 'redirect_uri': f"{base_url}/onedrive/authentication", + 'prompt': 'consent', + 'access_type': 'offline' + } + return { + 'type': 'ir.actions.act_url', + 'target': 'self', + 'url': f"{AUTHORITY}?{urls.url_encode(params)}", + } + + def action_get_gdrive_auth_code(self): + """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 } + 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': f"{base_url}/google_drive/authentication", + 'access_type': 'offline', + 'state': json.dumps(state), + 'approval_prompt': 'force', + } + auth_url = f"{GOOGLE_AUTH_ENDPOINT}?{urls.url_encode(params)}" + return { + 'type': 'ir.actions.act_url', + 'target': 'self', + 'url': auth_url, + } + + def generate_onedrive_refresh_token(self): + """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': f"{base_url}/onedrive/authentication", + 'refresh_token': self.onedrive_refresh_token, + } + try: + res = requests.post(token_url, data=data, headers=headers) + res.raise_for_status() + response = res.json() if res.ok else {} + if response: + 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), + }) + except requests.HTTPError as error: + _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 = 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': f"{base_url}/onedrive/authentication", + } + token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" + try: + res = requests.post(token_url, data=data, headers=headers) + res.raise_for_status() + response = res.json() if res.ok else {} + if response: + 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), + }) + except requests.HTTPError as error: + _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"} + data = { + 'refresh_token': self.gdrive_refresh_token, + 'client_id': self.gdrive_client_key, + 'client_secret': self.gdrive_client_secret, + 'grant_type': 'refresh_token', + } + try: + res = requests.post(GOOGLE_TOKEN_ENDPOINT, data=data, headers=headers) + res.raise_for_status() + response = res.json() if res.ok else {} + if response: + 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), + }) + except requests.HTTPError as error: + 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]. " + "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 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"} + data = { + 'code': authorize_code, + 'client_id': self.gdrive_client_key, + 'client_secret': self.gdrive_client_secret, + 'grant_type': 'authorization_code', + 'redirect_uri': f"{base_url}/google_drive/authentication", + } + try: + res = requests.post(GOOGLE_TOKEN_ENDPOINT, data=data, headers=headers) + res.raise_for_status() + response = res.json() if res.ok else {} + if response: + expires_in = response.get('expires_in', 0) + self.write({ + 'gdrive_access_token': response.get('access_token'), + 'gdrive_refresh_token': response.get('refresh_token'), + 'gdrive_token_validity': fields.Datetime.now() + timedelta( + seconds=expires_in) if expires_in else False, + }) + except requests.HTTPError: + error_msg = _( + "Something went wrong during your token generation. " + "Your authorization code may be invalid." + ) + raise UserError(error_msg) + + def get_dropbox_auth_url(self): + """Return dropbox authorization url""" + dbx_auth = dropbox.oauth.DropboxOAuth2FlowNoRedirect( + self.dropbox_client_key, + self.dropbox_client_secret, + token_access_type='offline') + return dbx_auth.start() + + def set_dropbox_refresh_token(self, auth_code): + """Generate and set the dropbox refresh token from authorization code""" + dbx_auth = dropbox.oauth.DropboxOAuth2FlowNoRedirect( + self.dropbox_client_key, + self.dropbox_client_secret, + token_access_type='offline') + outh_result = dbx_auth.finish(auth_code) + self.dropbox_refresh_token = outh_result.refresh_token + + @api.constrains('db_name') + def _check_db_credentials(self): + """Validate entered database name and master password""" + database_list = db.list_dbs(force=True) + if self.db_name not in database_list: + raise ValidationError(_("Invalid Database Name!")) + try: + odoo.service.db.check_super(self.master_pwd) + except Exception: + raise ValidationError(_("Invalid Master Password!")) + + def action_sftp_connection(self): + """Test the sftp and ftp connection using entered credentials""" + if self.backup_destination == 'sftp': + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + client.connect(hostname=self.sftp_host, + username=self.sftp_user, + password=self.sftp_password, + port=self.sftp_port) + sftp = client.open_sftp() + sftp.close() + except Exception as e: + raise UserError(_("SFTP Exception: %s", e)) + finally: + client.close() + elif self.backup_destination == 'ftp': + try: + ftp_server = ftplib.FTP() + ftp_server.connect(self.ftp_host, int(self.ftp_port)) + ftp_server.login(self.ftp_user, self.ftp_password) + ftp_server.quit() + except Exception as e: + raise UserError(_("FTP Exception: %s", e)) + self.active = self.hide_active = True + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': _("Connection Test Succeeded!"), + 'message': _("Everything seems properly set up!"), + 'sticky': False, + } + } + + @api.onchange('backup_destination') + def _onchange_back_up_local(self): + """ + On change handler for the 'backup_destination' field. This method is + triggered when the value of 'backup_destination' is changed. If the + chosen backup destination is 'local', it sets the 'hide_active' field + to True which make active field to readonly to False. + """ + if self.backup_destination == 'local': + self.hide_active = True + + 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([('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 = 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': + try: + if not os.path.isdir(rec.backup_path): + os.makedirs(rec.backup_path) + 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, rec.backup_frequency) + f.close() + # Remove older backups + if rec.auto_remove: + for filename in os.listdir(rec.backup_path): + file = os.path.join(rec.backup_path, filename) + create_time = datetime.fromtimestamp( + os.path.getctime(file)) + backup_duration = datetime.utcnow() - create_time + 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) + except Exception as e: + rec.generated_exception = e + _logger.info('FTP Exception: %s', e) + if rec.notify_user: + mail_template_failed.send_mail(rec.id, force_send=True) + # FTP backup + elif rec.backup_destination == 'ftp': + try: + ftp_server = ftplib.FTP() + ftp_server.connect(rec.ftp_host, int(rec.ftp_port)) + ftp_server.login(rec.ftp_user, rec.ftp_password) + ftp_server.encoding = "utf-8" + temp = tempfile.NamedTemporaryFile( + suffix='.%s' % rec.backup_format) + try: + ftp_server.cwd(rec.ftp_path) + except ftplib.error_perm: + ftp_server.mkd(rec.ftp_path) + 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_frequency) + ftp_server.storbinary('STOR %s' % backup_filename, + open(temp.name, "rb")) + if rec.auto_remove: + files = ftp_server.nlst() + for file in files: + create_time = datetime.strptime( + ftp_server.sendcmd('MDTM ' + file)[4:], + "%Y%m%d%H%M%S") + diff_days = ( + datetime.now() - create_time).days + if diff_days >= rec.days_to_remove: + ftp_server.delete(file) + ftp_server.quit() + if rec.notify_user: + mail_template_success.send_mail(rec.id, + force_send=True) + except Exception as e: + rec.generated_exception = e + _logger.info('FTP Exception: %s', e) + if rec.notify_user: + mail_template_failed.send_mail(rec.id, force_send=True) + # SFTP backup + elif rec.backup_destination == 'sftp': + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + client.connect(hostname=rec.sftp_host, + username=rec.sftp_user, + password=rec.sftp_password, + port=rec.sftp_port) + sftp = client.open_sftp() + 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, rec.backup_frequency) + try: + sftp.chdir(rec.sftp_path) + except IOError as e: + if e.errno == errno.ENOENT: + sftp.mkdir(rec.sftp_path) + sftp.chdir(rec.sftp_path) + sftp.put(temp.name, backup_filename) + if rec.auto_remove: + files = sftp.listdir() + expired = list(filter( + lambda fl: (fields.Datetime.now() + - datetime.fromtimestamp( + sftp.stat(fl).st_mtime)).days >= + rec.days_to_remove, files)) + for file in expired: + sftp.unlink(file) + sftp.close() + if rec.notify_user: + mail_template_success.send_mail(rec.id, + force_send=True) + except Exception as e: + rec.generated_exception = e + _logger.info('SFTP Exception: %s', e) + if rec.notify_user: + mail_template_failed.send_mail(rec.id, force_send=True) + finally: + client.close() + # Google Drive backup + elif rec.backup_destination == 'google_drive': + try: + if rec.gdrive_token_validity <= fields.Datetime.now(): + rec.generate_gdrive_refresh_token() + 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, rec.backup_frequency) + try: + headers = { + "Authorization": "Bearer %s" % rec.gdrive_access_token} + para = { + "name": backup_filename, + "parents": [rec.google_drive_folder_key], + } + files = { + 'data': ('metadata', json.dumps(para), + 'application/json; charset=UTF-8'), + 'file': open(temp.name, "rb") + } + requests.post( + "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart", + headers=headers, + files=files + ) + if rec.auto_remove: + query = "parents = '%s'" % rec.google_drive_folder_key + files_req = requests.get( + "https://www.googleapis.com/drive/v3/files?q=%s" % query, + headers=headers) + 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) + create_time = file_date_req.json()[ + 'createdTime'][ + :19].replace('T', ' ') + diff_days = ( + fields.Datetime.now() - datetime.strptime( + create_time, '%Y-%m-%d %H:%M:%S')).days + if diff_days >= rec.days_to_remove: + requests.delete( + "https://www.googleapis.com/drive/v3/files/%s" % + file['id'], headers=headers) + if rec.notify_user: + mail_template_success.send_mail(rec.id, + force_send=True) + except Exception as e: + + rec.generated_exception = e + _logger.info('Google Drive Exception: %s', e) + if rec.notify_user: + mail_template_failed.send_mail(rec.id, + force_send=True) + except Exception: + if rec.notify_user: + mail_template_failed.send_mail(rec.id, force_send=True) + raise ValidationError( + 'Please check the credentials before activation') + else: + raise ValidationError('Please check connection') + # Dropbox backup + elif rec.backup_destination == 'dropbox': + 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, rec.backup_frequency) + try: + dbx = dropbox.Dropbox( + app_key=rec.dropbox_client_key, + app_secret=rec.dropbox_client_secret, + oauth2_refresh_token=rec.dropbox_refresh_token) + dropbox_destination = (rec.dropbox_folder + '/' + + backup_filename) + dbx.files_upload(temp.read(), dropbox_destination) + if rec.auto_remove: + files = dbx.files_list_folder(rec.dropbox_folder) + file_entries = files.entries + expired_files = list(filter( + lambda fl: (fields.Datetime.now() - + fl.client_modified).days >= + rec.days_to_remove, + file_entries)) + for file in expired_files: + dbx.files_delete_v2(file.path_display) + if rec.notify_user: + mail_template_success.send_mail(rec.id, + force_send=True) + except Exception as error: + rec.generated_exception = error + _logger.info('Dropbox Exception: %s', error) + if rec.notify_user: + mail_template_failed.send_mail(rec.id, force_send=True) + # Onedrive Backup + elif rec.backup_destination == 'onedrive': + try: + if rec.onedrive_token_validity <= fields.Datetime.now(): + rec.generate_onedrive_refresh_token() + + with tempfile.NamedTemporaryFile(suffix=f'.{rec.backup_format}') as temp: + with open(temp.name, "wb+") as tmp: + self.dump_data(rec.db_name, tmp, rec.backup_format, rec.backup_frequency) + + headers = { + 'Authorization': f'Bearer {rec.onedrive_access_token}', + 'Content-Type': 'application/json' + } + + upload_session_url = ( + f"{MICROSOFT_GRAPH_END_POINT}/v1.0/me/drive/items/" + f"{rec.onedrive_folder_key}:/{backup_filename}:/createUploadSession" + ) + + upload_session = requests.post(upload_session_url, headers=headers) + upload_session.raise_for_status() + + upload_url = upload_session.json().get('uploadUrl') + if not upload_url: + raise ValueError("Failed to get upload URL from OneDrive") + + file_size = os.path.getsize(temp.name) + with open(temp.name, 'rb') as f: + headers_upload = { + 'Content-Length': str(file_size), + 'Content-Range': f'bytes 0-{file_size - 1}/{file_size}' + } + upload_response = requests.put(upload_url, headers=headers_upload, data=f) + upload_response.raise_for_status() + + if rec.auto_remove: + verify_url = ( + f"{MICROSOFT_GRAPH_END_POINT}/v1.0/me/drive/items/" + f"{rec.onedrive_folder_key}:/{backup_filename}" + ) + verify_response = requests.get(verify_url, headers=headers) + + if verify_response.status_code == 200: + list_url = ( + f"{MICROSOFT_GRAPH_END_POINT}/v1.0/me/drive/items/" + f"{rec.onedrive_folder_key}/children" + ) + response = requests.get(list_url, headers=headers) + response.raise_for_status() + + files = response.json().get('value', []) + current_time = fields.Datetime.now() + + for file in files: + if file['name'] == backup_filename: + continue + + create_time_str = file['createdDateTime'][:19].replace('T', ' ') + create_time = datetime.strptime(create_time_str, '%Y-%m-%d %H:%M:%S') + diff_days = (current_time - create_time).days + + if diff_days >= rec.days_to_remove: + delete_url = f"{MICROSOFT_GRAPH_END_POINT}/v1.0/me/drive/items/{file['id']}" + requests.delete(delete_url, headers=headers).raise_for_status() + + # Notify user on success + if rec.notify_user: + mail_template_success.send_mail(rec.id, force_send=True) + + except requests.exceptions.RequestException as req_error: + rec.generated_exception = str(req_error) + _logger.error('OneDrive API Error: %s', req_error, exc_info=True) + if rec.notify_user: + mail_template_failed.send_mail(rec.id, force_send=True) + + except Exception as error: + rec.generated_exception = str(error) + _logger.error('OneDrive Backup Error: %s', error, exc_info=True) + if rec.notify_user: + mail_template_failed.send_mail(rec.id, force_send=True) + elif rec.backup_destination == 'next_cloud': + try: + if rec.domain and rec.next_cloud_password and \ + rec.next_cloud_user_name: + try: + # Connect to NextCloud using the provided username + # and password + ncx = NextCloud(rec.domain, + auth=HTTPBasicAuth( + rec.next_cloud_user_name, + rec.next_cloud_password)) + # Connect to NextCloud again to perform additional + # operations + nc = nextcloud_client.Client(rec.domain) + nc.login(rec.next_cloud_user_name, + rec.next_cloud_password) + # Get the folder name from the NextCloud folder ID + folder_name = rec.nextcloud_folder_key + # If auto_remove is enabled, remove backup files + # older than specified days + if rec.auto_remove: + folder_path = "/" + folder_name + for item in nc.list(folder_path): + backup_file_name = item.path.split("/")[-1] + backup_date_str = \ + backup_file_name.split("_")[1] + backup_date = datetime.strptime( + backup_date_str, '%Y-%m-%d').date() + if (fields.date.today() - backup_date).days \ + >= rec.days_to_remove: + nc.delete(item.path) + # If notify_user is enabled, send a success email + # notification + if rec.notify_user: + mail_template_success.send_mail(rec.id, + force_send=True) + except Exception as error: + rec.generated_exception = error + _logger.info('NextCloud Exception: %s', error) + if rec.notify_user: + # If an exception occurs, send a failed email + # notification + mail_template_failed.send_mail(rec.id, + force_send=True) + # Get the list of folders in the root directory of NextCloud + data = ncx.list_folders('/').__dict__ + folders = [ + [file_name['href'].split('/')[-2], + file_name['file_id']] + for file_name in data['data'] if + file_name['href'].endswith('/')] + # If the folder name is not found in the list of folders, + # create the folder + if folder_name not in [file[0] for file in folders]: + nc.mkdir(folder_name) + # 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, 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_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, 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_name) + except Exception: + raise ValidationError('Please check connection') + # Amazon S3 Backup + elif rec.backup_destination == 'amazon_s3': + if rec.aws_access_key and rec.aws_secret_access_key: + try: + # Create a boto3 client for Amazon S3 with provided + # access key id and secret access key + bo3 = boto3.client( + 's3', + aws_access_key_id=rec.aws_access_key, + aws_secret_access_key=rec.aws_secret_access_key) + # If auto_remove is enabled, remove the backups that + # are older than specified days from the S3 bucket + if rec.auto_remove: + folder_path = rec.aws_folder_name + response = bo3.list_objects( + Bucket=rec.bucket_file_name, + Prefix=folder_path) + today = fields.date.today() + for file in response['Contents']: + file_path = file['Key'] + last_modified = file['LastModified'] + date = last_modified.date() + age_in_days = (today - date).days + if age_in_days >= rec.days_to_remove: + bo3.delete_object( + Bucket=rec.bucket_file_name, + Key=file_path) + # Create a boto3 resource for Amazon S3 with provided + # access key id and secret access key + s3 = boto3.resource( + 's3', + aws_access_key_id=rec.aws_access_key, + aws_secret_access_key=rec.aws_secret_access_key) + # Create a folder in the specified bucket, if it + # doesn't already exist + s3.Object(rec.bucket_file_name, + rec.aws_folder_name + '/').put() + bucket = s3.Bucket(rec.bucket_file_name) + # Get all the prefixes in the bucket + prefixes = set() + for obj in bucket.objects.all(): + key = obj.key + if key.endswith('/'): + prefix = key[:-1] # Remove the trailing slash + 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 + 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, 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_name) + # If notify_user is enabled, send an email to the + # user notifying them about the successful backup + if rec.notify_user: + mail_template_success.send_mail(rec.id, + force_send=True) + except Exception as error: + # If any error occurs, set the 'generated_exception' + # field to the error message and log the error + rec.generated_exception = error + _logger.info('Amazon S3 Exception: %s', error) + # If notify_user is enabled, email the user + # notifying them about the failed backup + if rec.notify_user: + mail_template_failed.send_mail(rec.id, force_send=True) + + 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(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() + if backup_format == 'zip': + with tempfile.TemporaryDirectory() as dump_dir: + filestore = odoo.tools.config.filestore(db_name) + cmd.insert(-1,'--file=' + os.path.join(dump_dir, 'dump.sql')) + subprocess.run(cmd, env=env, stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT, check=True) + if os.path.exists(filestore): + shutil.copytree(filestore, + os.path.join(dump_dir, 'filestore')) + with open(os.path.join(dump_dir, 'manifest.json'), 'w') as fh: + db = odoo.sql_db.db_connect(db_name) + with db.cursor() as cr: + json.dump(self._dump_db_manifest(cr), fh, indent=4) + if stream: + odoo.tools.osutil.zip_dir(dump_dir, stream, + include_dir=False, + fnct_sort=lambda + file_name: file_name != 'dump.sql') + else: + t = tempfile.TemporaryFile() + odoo.tools.osutil.zip_dir(dump_dir, t, include_dir=False, + fnct_sort=lambda + file_name: file_name != 'dump.sql') + t.seek(0) + return t + else: + cmd.insert(-1,'--format=c') + process = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE) + stdout, _ = process.communicate() + if stream: + stream.write(stdout) + else: + return stdout + + def _dump_db_manifest(self, cr): + """ This function generates a manifest dictionary for database dump.""" + pg_version = "%d.%d" % divmod(cr._obj.connection.server_version / 100, 100) + cr.execute( + "SELECT name, latest_version FROM ir_module_module WHERE state = 'installed'") + modules = dict(cr.fetchall()) + manifest = { + 'odoo_dump': '1', + 'db_name': cr.dbname, + 'version': odoo.release.version, + 'version_info': odoo.release.version_info, + 'major_version': odoo.release.major_version, + 'pg_version': pg_version, + 'modules': modules, + } + return manifest diff --git a/auto_database_backup/security/ir.model.access.csv b/auto_database_backup/security/ir.model.access.csv new file mode 100755 index 000000000..8d4ff9c61 --- /dev/null +++ b/auto_database_backup/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_db_backup_configure_user,access.db.backup.configure.user,model_db_backup_configure,base.group_user,1,1,1,1 +access_dropbox_auth_code_user,access.dropbox.auth.code.user,model_dropbox_auth_code,base.group_user,1,1,1,1 diff --git a/auto_database_backup/static/description/assets/cybro-icon.png b/auto_database_backup/static/description/assets/cybro-icon.png new file mode 100755 index 000000000..06e73e11d Binary files /dev/null and b/auto_database_backup/static/description/assets/cybro-icon.png differ diff --git a/auto_database_backup/static/description/assets/cybro-odoo.png b/auto_database_backup/static/description/assets/cybro-odoo.png new file mode 100755 index 000000000..ed02e07a4 Binary files /dev/null and b/auto_database_backup/static/description/assets/cybro-odoo.png differ diff --git a/auto_database_backup/static/description/assets/h2.png b/auto_database_backup/static/description/assets/h2.png new file mode 100755 index 000000000..0bfc4707d Binary files /dev/null and b/auto_database_backup/static/description/assets/h2.png differ diff --git a/auto_database_backup/static/description/assets/icons/ajmaljk.png b/auto_database_backup/static/description/assets/icons/ajmaljk.png new file mode 100644 index 000000000..e485bd8c9 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/ajmaljk.png differ diff --git a/auto_database_backup/static/description/assets/icons/arrows-repeat.svg b/auto_database_backup/static/description/assets/icons/arrows-repeat.svg new file mode 100755 index 000000000..1d7efabc5 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/arrows-repeat.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup1.png b/auto_database_backup/static/description/assets/icons/auto_database_backup1.png new file mode 100644 index 000000000..93faea677 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup1.png differ diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup10.png b/auto_database_backup/static/description/assets/icons/auto_database_backup10.png new file mode 100644 index 000000000..7a415b0e2 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup10.png differ diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup11.png b/auto_database_backup/static/description/assets/icons/auto_database_backup11.png new file mode 100644 index 000000000..12a07a449 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup11.png differ diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup12.png b/auto_database_backup/static/description/assets/icons/auto_database_backup12.png new file mode 100644 index 000000000..abc6a7d34 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup12.png differ diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup13.png b/auto_database_backup/static/description/assets/icons/auto_database_backup13.png new file mode 100644 index 000000000..9fa13e432 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup13.png differ diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup2.png b/auto_database_backup/static/description/assets/icons/auto_database_backup2.png new file mode 100644 index 000000000..a8cb77759 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup2.png differ diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup3.png b/auto_database_backup/static/description/assets/icons/auto_database_backup3.png new file mode 100644 index 000000000..9ef262076 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup3.png differ diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup4.png b/auto_database_backup/static/description/assets/icons/auto_database_backup4.png new file mode 100644 index 000000000..82857e253 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup4.png differ diff --git a/auto_database_backup/static/description/assets/icons/auto_database_backup5.png b/auto_database_backup/static/description/assets/icons/auto_database_backup5.png new file mode 100644 index 000000000..fc9a9e6bb Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/auto_database_backup5.png differ diff --git a/auto_database_backup/static/description/assets/icons/banner-1.png b/auto_database_backup/static/description/assets/icons/banner-1.png new file mode 100755 index 000000000..c180db172 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/banner-1.png differ diff --git a/auto_database_backup/static/description/assets/icons/banner-2.svg b/auto_database_backup/static/description/assets/icons/banner-2.svg new file mode 100755 index 000000000..e606d97d9 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/banner-2.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/banner-bg.png b/auto_database_backup/static/description/assets/icons/banner-bg.png new file mode 100755 index 000000000..a8238d3c0 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/banner-bg.png differ diff --git a/auto_database_backup/static/description/assets/icons/banner-bg.svg b/auto_database_backup/static/description/assets/icons/banner-bg.svg new file mode 100755 index 000000000..b1378103e --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/banner-bg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/banner-call.svg b/auto_database_backup/static/description/assets/icons/banner-call.svg new file mode 100755 index 000000000..96c687e81 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/banner-call.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/auto_database_backup/static/description/assets/icons/banner-mail.svg b/auto_database_backup/static/description/assets/icons/banner-mail.svg new file mode 100755 index 000000000..cbf0d158d --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/banner-mail.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/auto_database_backup/static/description/assets/icons/banner-pattern.svg b/auto_database_backup/static/description/assets/icons/banner-pattern.svg new file mode 100755 index 000000000..9c1c7e101 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/banner-pattern.svg @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/banner-promo.svg b/auto_database_backup/static/description/assets/icons/banner-promo.svg new file mode 100755 index 000000000..d52791b11 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/banner-promo.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/blog-icon.png b/auto_database_backup/static/description/assets/icons/blog-icon.png new file mode 100644 index 000000000..ba4c7c366 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/blog-icon.png differ diff --git a/auto_database_backup/static/description/assets/icons/brand-pair.svg b/auto_database_backup/static/description/assets/icons/brand-pair.svg new file mode 100755 index 000000000..d8db7fc1e --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/brand-pair.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/check.png b/auto_database_backup/static/description/assets/icons/check.png new file mode 100755 index 000000000..c8e85f51d Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/check.png differ diff --git a/auto_database_backup/static/description/assets/icons/chevron.png b/auto_database_backup/static/description/assets/icons/chevron.png new file mode 100755 index 000000000..2089293d6 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/chevron.png differ diff --git a/auto_database_backup/static/description/assets/icons/close-icon.svg b/auto_database_backup/static/description/assets/icons/close-icon.svg new file mode 100755 index 000000000..df8cce37a --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/close-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/auto_database_backup/static/description/assets/icons/cogs.png b/auto_database_backup/static/description/assets/icons/cogs.png new file mode 100755 index 000000000..95d0bad62 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/cogs.png differ diff --git a/auto_database_backup/static/description/assets/icons/collabarate-icon.svg b/auto_database_backup/static/description/assets/icons/collabarate-icon.svg new file mode 100755 index 000000000..dd4e10518 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/collabarate-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/auto_database_backup/static/description/assets/icons/consultation.png b/auto_database_backup/static/description/assets/icons/consultation.png new file mode 100755 index 000000000..8319d4baa Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/consultation.png differ diff --git a/auto_database_backup/static/description/assets/icons/copylink.svg b/auto_database_backup/static/description/assets/icons/copylink.svg new file mode 100644 index 000000000..3b67f60e0 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/copylink.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/cybro-logo.png b/auto_database_backup/static/description/assets/icons/cybro-logo.png new file mode 100755 index 000000000..ff4b78220 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/cybro-logo.png differ diff --git a/auto_database_backup/static/description/assets/icons/down.svg b/auto_database_backup/static/description/assets/icons/down.svg new file mode 100755 index 000000000..f21c36271 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/auto_database_backup/static/description/assets/icons/ecom-black.png b/auto_database_backup/static/description/assets/icons/ecom-black.png new file mode 100755 index 000000000..a9385ff13 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/ecom-black.png differ diff --git a/auto_database_backup/static/description/assets/icons/education-black.png b/auto_database_backup/static/description/assets/icons/education-black.png new file mode 100755 index 000000000..3eb09b27b Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/education-black.png differ diff --git a/auto_database_backup/static/description/assets/icons/faq.png b/auto_database_backup/static/description/assets/icons/faq.png new file mode 100755 index 000000000..4250b5b81 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/faq.png differ diff --git a/auto_database_backup/static/description/assets/icons/feature-icon.svg b/auto_database_backup/static/description/assets/icons/feature-icon.svg new file mode 100755 index 000000000..fa0ea6850 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/feature-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/feature.png b/auto_database_backup/static/description/assets/icons/feature.png new file mode 100755 index 000000000..ac7a785c0 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/feature.png differ diff --git a/auto_database_backup/static/description/assets/icons/gear.svg b/auto_database_backup/static/description/assets/icons/gear.svg new file mode 100755 index 000000000..0cc66b6ea --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/gear.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/hero.gif b/auto_database_backup/static/description/assets/icons/hero.gif new file mode 100755 index 000000000..380654dfe Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/hero.gif differ diff --git a/auto_database_backup/static/description/assets/icons/hire-odoo.svg b/auto_database_backup/static/description/assets/icons/hire-odoo.svg new file mode 100755 index 000000000..e1ac089b0 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/hire-odoo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/hotel-black.png b/auto_database_backup/static/description/assets/icons/hotel-black.png new file mode 100755 index 000000000..130f613be Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/hotel-black.png differ diff --git a/auto_database_backup/static/description/assets/icons/license.png b/auto_database_backup/static/description/assets/icons/license.png new file mode 100755 index 000000000..a5869797e Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/license.png differ diff --git a/auto_database_backup/static/description/assets/icons/life-ring-icon.svg b/auto_database_backup/static/description/assets/icons/life-ring-icon.svg new file mode 100755 index 000000000..3ae6e1d89 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/life-ring-icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/lifebuoy.png b/auto_database_backup/static/description/assets/icons/lifebuoy.png new file mode 100755 index 000000000..658d56ccc Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/lifebuoy.png differ diff --git a/auto_database_backup/static/description/assets/icons/mail.svg b/auto_database_backup/static/description/assets/icons/mail.svg new file mode 100755 index 000000000..1eedde695 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/mail.svg @@ -0,0 +1,3 @@ + + + diff --git a/auto_database_backup/static/description/assets/icons/manufacturing-black.png b/auto_database_backup/static/description/assets/icons/manufacturing-black.png new file mode 100755 index 000000000..697eb0e9f Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/manufacturing-black.png differ diff --git a/auto_database_backup/static/description/assets/icons/notes.png b/auto_database_backup/static/description/assets/icons/notes.png new file mode 100755 index 000000000..ee5e95404 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/notes.png differ diff --git a/auto_database_backup/static/description/assets/icons/notification icon.svg b/auto_database_backup/static/description/assets/icons/notification icon.svg new file mode 100755 index 000000000..053189973 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/notification icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/odoo-consultancy.svg b/auto_database_backup/static/description/assets/icons/odoo-consultancy.svg new file mode 100755 index 000000000..e05f65bde --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/odoo-consultancy.svg @@ -0,0 +1,4 @@ + + + + diff --git a/auto_database_backup/static/description/assets/icons/odoo-licencing.svg b/auto_database_backup/static/description/assets/icons/odoo-licencing.svg new file mode 100755 index 000000000..2606c88b0 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/odoo-licencing.svg @@ -0,0 +1,3 @@ + + + diff --git a/auto_database_backup/static/description/assets/icons/odoo-logo.png b/auto_database_backup/static/description/assets/icons/odoo-logo.png new file mode 100755 index 000000000..0e4d0eb5a Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/odoo-logo.png differ diff --git a/auto_database_backup/static/description/assets/icons/patter.svg b/auto_database_backup/static/description/assets/icons/patter.svg new file mode 100755 index 000000000..25c9c0a8f --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/patter.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/pattern1.png b/auto_database_backup/static/description/assets/icons/pattern1.png new file mode 100755 index 000000000..09ab0fb2d Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/pattern1.png differ diff --git a/auto_database_backup/static/description/assets/icons/pos-black.png b/auto_database_backup/static/description/assets/icons/pos-black.png new file mode 100755 index 000000000..97c0f90c1 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/pos-black.png differ diff --git a/auto_database_backup/static/description/assets/icons/puzzle-piece-icon.svg b/auto_database_backup/static/description/assets/icons/puzzle-piece-icon.svg new file mode 100755 index 000000000..3e9ad9373 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/puzzle-piece-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/puzzle.png b/auto_database_backup/static/description/assets/icons/puzzle.png new file mode 100755 index 000000000..65cf854e7 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/puzzle.png differ diff --git a/auto_database_backup/static/description/assets/icons/replace-icon.svg b/auto_database_backup/static/description/assets/icons/replace-icon.svg new file mode 100755 index 000000000..d0e3a7af1 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/replace-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/restaurant-black.png b/auto_database_backup/static/description/assets/icons/restaurant-black.png new file mode 100755 index 000000000..4a35eb939 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/restaurant-black.png differ diff --git a/auto_database_backup/static/description/assets/icons/screenshot-main.png b/auto_database_backup/static/description/assets/icons/screenshot-main.png new file mode 100755 index 000000000..575f8e676 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/screenshot-main.png differ diff --git a/auto_database_backup/static/description/assets/icons/screenshot.png b/auto_database_backup/static/description/assets/icons/screenshot.png new file mode 100755 index 000000000..cef272529 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/screenshot.png differ diff --git a/auto_database_backup/static/description/assets/icons/service-black.png b/auto_database_backup/static/description/assets/icons/service-black.png new file mode 100755 index 000000000..301ab51cb Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/service-black.png differ diff --git a/auto_database_backup/static/description/assets/icons/skype-fill.svg b/auto_database_backup/static/description/assets/icons/skype-fill.svg new file mode 100755 index 000000000..c17423639 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/skype-fill.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/skype.png b/auto_database_backup/static/description/assets/icons/skype.png new file mode 100755 index 000000000..51b409fb3 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/skype.png differ diff --git a/auto_database_backup/static/description/assets/icons/skype.svg b/auto_database_backup/static/description/assets/icons/skype.svg new file mode 100755 index 000000000..df3dad39b --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/skype.svg @@ -0,0 +1,3 @@ + + + diff --git a/auto_database_backup/static/description/assets/icons/star-1.svg b/auto_database_backup/static/description/assets/icons/star-1.svg new file mode 100755 index 000000000..7e55ab162 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/star-1.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/star-2.svg b/auto_database_backup/static/description/assets/icons/star-2.svg new file mode 100755 index 000000000..5ae9f507a --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/star-2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/support.png b/auto_database_backup/static/description/assets/icons/support.png new file mode 100755 index 000000000..4f18b8b82 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/support.png differ diff --git a/auto_database_backup/static/description/assets/icons/test-1 - Copy.png b/auto_database_backup/static/description/assets/icons/test-1 - Copy.png new file mode 100755 index 000000000..f6a902663 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/test-1 - Copy.png differ diff --git a/auto_database_backup/static/description/assets/icons/test-1.png b/auto_database_backup/static/description/assets/icons/test-1.png new file mode 100755 index 000000000..0908add2b Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/test-1.png differ diff --git a/auto_database_backup/static/description/assets/icons/test-2.png b/auto_database_backup/static/description/assets/icons/test-2.png new file mode 100755 index 000000000..4671fe91e Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/test-2.png differ diff --git a/auto_database_backup/static/description/assets/icons/trading-black.png b/auto_database_backup/static/description/assets/icons/trading-black.png new file mode 100755 index 000000000..9398ba2f1 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/trading-black.png differ diff --git a/auto_database_backup/static/description/assets/icons/training.png b/auto_database_backup/static/description/assets/icons/training.png new file mode 100755 index 000000000..884ca024d Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/training.png differ diff --git a/auto_database_backup/static/description/assets/icons/translate.svg b/auto_database_backup/static/description/assets/icons/translate.svg new file mode 100755 index 000000000..af9c8a1aa --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/translate.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/update.png b/auto_database_backup/static/description/assets/icons/update.png new file mode 100755 index 000000000..ecbc5a01a Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/update.png differ diff --git a/auto_database_backup/static/description/assets/icons/user.png b/auto_database_backup/static/description/assets/icons/user.png new file mode 100755 index 000000000..6ffb23d9f Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/user.png differ diff --git a/auto_database_backup/static/description/assets/icons/video.png b/auto_database_backup/static/description/assets/icons/video.png new file mode 100755 index 000000000..576705b17 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/video.png differ diff --git a/auto_database_backup/static/description/assets/icons/whatsapp.png b/auto_database_backup/static/description/assets/icons/whatsapp.png new file mode 100755 index 000000000..d513a5356 Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/whatsapp.png differ diff --git a/auto_database_backup/static/description/assets/icons/whatsapp.svg b/auto_database_backup/static/description/assets/icons/whatsapp.svg new file mode 100644 index 000000000..bba9ca395 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/whatsapp.svg @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/auto_database_backup/static/description/assets/icons/wrench-icon.svg b/auto_database_backup/static/description/assets/icons/wrench-icon.svg new file mode 100755 index 000000000..174b5a465 --- /dev/null +++ b/auto_database_backup/static/description/assets/icons/wrench-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/auto_database_backup/static/description/assets/icons/wrench.png b/auto_database_backup/static/description/assets/icons/wrench.png new file mode 100755 index 000000000..6c04dea0f Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/wrench.png differ diff --git a/auto_database_backup/static/description/assets/icons/youtube-icon.png b/auto_database_backup/static/description/assets/icons/youtube-icon.png new file mode 100644 index 000000000..f206560dc Binary files /dev/null and b/auto_database_backup/static/description/assets/icons/youtube-icon.png 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.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/4.png b/auto_database_backup/static/description/assets/modules/4.png new file mode 100644 index 000000000..00ebf54ad Binary files /dev/null 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/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/screenshots/1.png b/auto_database_backup/static/description/assets/screenshots/1.png new file mode 100755 index 000000000..406e66aea Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/1.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon1.png b/auto_database_backup/static/description/assets/screenshots/amazon1.png new file mode 100644 index 000000000..52357df9a Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon1.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon10.png b/auto_database_backup/static/description/assets/screenshots/amazon10.png new file mode 100644 index 000000000..7fe959569 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon10.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon12.png b/auto_database_backup/static/description/assets/screenshots/amazon12.png new file mode 100644 index 000000000..f9345a6d8 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon12.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon2.png b/auto_database_backup/static/description/assets/screenshots/amazon2.png new file mode 100644 index 000000000..5fcd336d6 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon2.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon4.png b/auto_database_backup/static/description/assets/screenshots/amazon4.png new file mode 100644 index 000000000..651ec6a7f Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon4.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon5.png b/auto_database_backup/static/description/assets/screenshots/amazon5.png new file mode 100644 index 000000000..20acea7e6 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon5.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon6.png b/auto_database_backup/static/description/assets/screenshots/amazon6.png new file mode 100644 index 000000000..22bbce54c Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon6.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon7.png b/auto_database_backup/static/description/assets/screenshots/amazon7.png new file mode 100644 index 000000000..c50a20cc8 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon7.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon8.png b/auto_database_backup/static/description/assets/screenshots/amazon8.png new file mode 100644 index 000000000..415d521c4 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon8.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazon9.png b/auto_database_backup/static/description/assets/screenshots/amazon9.png new file mode 100644 index 000000000..284490127 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazon9.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/amazons3.png b/auto_database_backup/static/description/assets/screenshots/amazons3.png new file mode 100755 index 000000000..5e91106df Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/amazons3.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/backep2.png b/auto_database_backup/static/description/assets/screenshots/backep2.png new file mode 100755 index 000000000..4b21643c3 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/backep2.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/backup.png b/auto_database_backup/static/description/assets/screenshots/backup.png new file mode 100755 index 000000000..ff4056392 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/backup.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/drop2.png b/auto_database_backup/static/description/assets/screenshots/drop2.png new file mode 100755 index 000000000..9f17d8b89 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/drop2.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/drop3.png b/auto_database_backup/static/description/assets/screenshots/drop3.png new file mode 100755 index 000000000..1629c9ccc Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/drop3.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/drop4.png b/auto_database_backup/static/description/assets/screenshots/drop4.png new file mode 100644 index 000000000..68900baa9 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/drop4.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/drop5.png b/auto_database_backup/static/description/assets/screenshots/drop5.png new file mode 100755 index 000000000..b2c280665 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/drop5.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/drop6.png b/auto_database_backup/static/description/assets/screenshots/drop6.png new file mode 100755 index 000000000..123cc46a2 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/drop6.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/drop7.png b/auto_database_backup/static/description/assets/screenshots/drop7.png new file mode 100755 index 000000000..d200e0363 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/drop7.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/drop8.png b/auto_database_backup/static/description/assets/screenshots/drop8.png new file mode 100644 index 000000000..665779ef1 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/drop8.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/dropbox`1.png b/auto_database_backup/static/description/assets/screenshots/dropbox`1.png new file mode 100755 index 000000000..977167b38 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/dropbox`1.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/failure_mail.png b/auto_database_backup/static/description/assets/screenshots/failure_mail.png new file mode 100644 index 000000000..5e8a6bb8e Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/failure_mail.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/ftp.png b/auto_database_backup/static/description/assets/screenshots/ftp.png new file mode 100644 index 000000000..9ef05b303 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/ftp.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/googl 4.png b/auto_database_backup/static/description/assets/screenshots/googl 4.png new file mode 100755 index 000000000..f59931a33 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/googl 4.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google 2.png b/auto_database_backup/static/description/assets/screenshots/google 2.png new file mode 100644 index 000000000..0aa2e73b7 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google 2.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google 3.png b/auto_database_backup/static/description/assets/screenshots/google 3.png new file mode 100755 index 000000000..d035cfc1c Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google 3.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google 5.png b/auto_database_backup/static/description/assets/screenshots/google 5.png new file mode 100755 index 000000000..d6462d690 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google 5.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 new file mode 100644 index 000000000..62a8fa3d1 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google 8.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google.png b/auto_database_backup/static/description/assets/screenshots/google.png new file mode 100755 index 000000000..a29584a60 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google3.png b/auto_database_backup/static/description/assets/screenshots/google3.png new file mode 100755 index 000000000..f88fac7da Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google3.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google6.png b/auto_database_backup/static/description/assets/screenshots/google6.png new file mode 100644 index 000000000..9708cafb0 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google6.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/google7.png b/auto_database_backup/static/description/assets/screenshots/google7.png new file mode 100755 index 000000000..f2c492495 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/google7.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..c7519f067 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 new file mode 100644 index 000000000..dc1fac34a Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/local.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/next2.png b/auto_database_backup/static/description/assets/screenshots/next2.png new file mode 100755 index 000000000..30b7eaf36 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/next2.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/next_cloud_9.png b/auto_database_backup/static/description/assets/screenshots/next_cloud_9.png new file mode 100644 index 000000000..261d476f4 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/next_cloud_9.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/nextcloud1.png b/auto_database_backup/static/description/assets/screenshots/nextcloud1.png new file mode 100644 index 000000000..64c5bfd75 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/nextcloud1.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/nextcloud_4.png b/auto_database_backup/static/description/assets/screenshots/nextcloud_4.png new file mode 100644 index 000000000..a0fbb2f36 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/nextcloud_4.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/nextcloud_create_3.png b/auto_database_backup/static/description/assets/screenshots/nextcloud_create_3.png new file mode 100644 index 000000000..2548aa71e Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/nextcloud_create_3.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/notify.png b/auto_database_backup/static/description/assets/screenshots/notify.png new file mode 100644 index 000000000..05e7392a5 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/notify.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/onedrive 2.png b/auto_database_backup/static/description/assets/screenshots/onedrive 2.png new file mode 100755 index 000000000..1b942d3cd Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/onedrive 2.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 new file mode 100644 index 000000000..af54f5c84 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/onedrive 4.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/onedrive 6.png b/auto_database_backup/static/description/assets/screenshots/onedrive 6.png new file mode 100755 index 000000000..6af4f30ae Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/onedrive 6.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/onedrive.png b/auto_database_backup/static/description/assets/screenshots/onedrive.png new file mode 100755 index 000000000..e188046bb Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/onedrive.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/onedrive3.png b/auto_database_backup/static/description/assets/screenshots/onedrive3.png new file mode 100755 index 000000000..56c1dcff3 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/onedrive3.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/onedrive4.png b/auto_database_backup/static/description/assets/screenshots/onedrive4.png new file mode 100644 index 000000000..9fd4519d6 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/onedrive4.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/onedrive5.png b/auto_database_backup/static/description/assets/screenshots/onedrive5.png new file mode 100644 index 000000000..ae50f70a6 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/onedrive5.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/onedrive7.png b/auto_database_backup/static/description/assets/screenshots/onedrive7.png new file mode 100755 index 000000000..7738ec9f0 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/onedrive7.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/remove.png b/auto_database_backup/static/description/assets/screenshots/remove.png new file mode 100644 index 000000000..46d65cf56 Binary files /dev/null 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 new file mode 100644 index 000000000..d42c24ef6 Binary files /dev/null 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 new file mode 100644 index 000000000..6da692e7c Binary files /dev/null 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 new file mode 100644 index 000000000..ce0b4d263 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/sftp.png differ diff --git a/auto_database_backup/static/description/assets/screenshots/success_mail.png b/auto_database_backup/static/description/assets/screenshots/success_mail.png new file mode 100644 index 000000000..05e7392a5 Binary files /dev/null and b/auto_database_backup/static/description/assets/screenshots/success_mail.png differ diff --git a/auto_database_backup/static/description/assets/y18.jpg b/auto_database_backup/static/description/assets/y18.jpg new file mode 100755 index 000000000..eea1714f2 Binary files /dev/null and b/auto_database_backup/static/description/assets/y18.jpg differ diff --git a/auto_database_backup/static/description/banner.gif b/auto_database_backup/static/description/banner.gif new file mode 100644 index 000000000..c45049986 Binary files /dev/null and b/auto_database_backup/static/description/banner.gif differ diff --git a/auto_database_backup/static/description/icon.png b/auto_database_backup/static/description/icon.png new file mode 100755 index 000000000..991118cd6 Binary files /dev/null and b/auto_database_backup/static/description/icon.png differ diff --git a/auto_database_backup/static/description/index.html b/auto_database_backup/static/description/index.html new file mode 100644 index 000000000..4719fc97a --- /dev/null +++ b/auto_database_backup/static/description/index.html @@ -0,0 +1,2183 @@ + + + + + + Automatic Database Backup + + + + + + + + + + +
+
+ + + +
+
+
+
+
+
+ +
+ Supports: +
+ Community +
+
+ Enterprise +
+
+
+
+
+ Availability: +
+ On Premise +
+
+ Odoo Online +
+
+ Odoo.sh +
+
+
+
+
+
+
+ +
+
+
+
+

+ This Module Helps To Generate Automated Backup + Of Databases. +

+

Automatic Database Backup Odoo19 +

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

+ Blog and Video Details +

+
+
+
+
+ +
+

Read Blog

+

Read Our Detailed Blog

+
+
+ +
+

+ https://www.cybrosys.com/blog/how-to-manage-automatic-database-backup-in-odoo-18 +

+
+
+
+
+
+
+ +
+

Video Tutorial

+

Watch Detailed Demo on Youtube

+ Watch Demo +
+
+
+
+ + +
+
+
+ +
+ This module uses some external python dependencies : + dropbox, pyncclient , nextcloud-api-wrapper , boto3 and paramiko. Before + installing the module install the python + package + first. The required python packages can be installed using the + following commands. +
+
+ pip + install dropbox + pip + install pyncclient + pip + install nextcloud-api-wrapper + pip + install boto3 + pip + install paramiko +
+
+
+
+ + +
+
+
+ Automatic Database Backup +

+ Are you ready to make your business more + organized? +
Improve now! +

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

+ KEY HIGHLIGHTS +

+
+
+
+
+ +
+
+

+ Automatic Backup to Local Server

+

+ Generate Database Backups on regular intervals to your Local Server

+
+
+
+
+
+
+ +
+
+

+ Automatic Backup to Remote Server

+

+ Generate Database Backups on regular intervals to your Remote Server

+
+
+
+
+
+
+ +
+
+

+ Automatic Backup to Google Drive

+

+ Generate Database Backups on regular intervals to Google Drive +

+
+
+
+
+
+
+ +
+
+

+ Automatic Backup to Dropbox

+

+ Generate Database Backups on regular intervals to Dropbox

+
+
+
+
+
+
+ +
+
+

+ Automatic Backup to Onedrive

+

+ Generate Database Backups on regular intervals to Onedrive

+
+
+
+
+
+
+ +
+
+

+ Automatic Backup to Nextcloud

+

+ Generate Database Backups on regular intervals to Nextcloud

+
+
+
+
+
+
+ +
+
+

+ Automatic Backup to Amazon S3

+

+ Generate Database Backups on regular intervals to Amazon S3

+
+
+
+
+
+
+ +
+
+

+ Notification Regarding Backup

+

+ Notify user on success and failure of backup generation.

+
+
+
+
+
+
+ +
+
+

+ Remove Old Backups

+

+ Automatically remove old backups that consumes storage space

+
+
+
+
+
+
+ +
+
+

+ Easy Configuration

+

+ You can easily set up the configuration for backup to save in multiple Locations

+
+
+
+ +
+
+ + + + +
+
+ +
+
+
+
+ acc_bg +
+ +
+
+
+
+

+ Database Backup Configuration + + Menu +

+
+
+

+ Go to Setting --> Technical --> + Backup Configuration to + configure backups. +

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

+ Create New + + Database Backup Configuration. +

+
+
+

+ Enter the Database Name and + Master Password. Specify Backup + Destination. Enter the backup + directory path, if directory + does not exist new directory + will be created. +

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

+ Backup + Frequency +

+
+
+

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

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

+ Store Backup to Remote + + SFTP Server. +

+
+
+

+ Select Backup Destination as + SFTP, enter credentials. "TEST + CONNECTION" button to check + whether the connection is + successful. +

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

+ Store Backup to Remote + + + FTP Server. +

+
+
+

+ Select Backup Destination as + FTP, enter credentials. "TEST + CONNECTION" button to check + whether the connection is + successful. +

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

+ Store Backup to + + + Google Drive +

+
+
+

+ 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: +

+
+
+
+ +
+
+
+

+ Enable API and Services +

+
+
+
+ +
+
+
+

+ Enable Google Drive API +

+
+
+
+ +
+
+
+

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

+
+
+
+ +
+
+
+

+ 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 +

+
+
+
+ +
+
+
+

+ 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. +

+
+
+
+ +
+
+
+

+ Grant Access +

+
+
+
+ +
+
+
+

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

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

+ Store Backup to + + + Dropbox. +

+
+
+

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

+
+
+
+ +
+
+
+

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

+
+
+
+ +
+
+
+

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

+
+
+
+ +
+
+
+

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

+
+
+
+ +
+
+
+

+ Get the Authorization Code and click confirm. +

+
+
+
+ +
+
+
+

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

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

+ Store Backup to + + + Onedrive. +

+
+
+

+ 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: +

+
+
+
+ +
+
+
+

+ Copy the Client ID and Generate Client Secret. +

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

+ Add Scope in the Expose an API page. +

+
+ +
+
+ +
+
+ +
+

+ Get OneDrive folder ID, where need to store the backup files. +

+
+
+
+ +
+
+
+

+ Configure the Backup. +

+
+
+
+ +
+
+
+

+ Setup Token, it will be redirected to an authorization page. +

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

+ Store Backup to + + + NextCloud. +

+
+
+

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

+
+
+
+ +
+
+
+

+ 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. +

+
+
+
+ +
+
+
+

+ 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. +

+
+
+
+ +
+
+
+

+ 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. +

+
+
+
+ +
+
+
+

+ 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. +

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

+ Store Backup to + + + AmazonS3. +

+
+
+

+ 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 . +

+
+
+
+ +
+
+
+

+ 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. +

+
+
+ +
+
+
+

+ 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. +

+
+
+ +
+
+
+

+ 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. +

+
+
+ +
+
+
+

+ 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.

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

+ Automatically Remove + + Old Backups. +

+
+
+

+ Enable auto remove option, specify number of days to remove backups. +

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

+ Notify User on Success and Failure of + + Backup Generation. +

+
+
+

+ 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. +

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

+ Successful backup + + notification email. +

+
+
+

+

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

+ Failed backup + + notification email. +

+
+
+

+

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

+ Scheduled Actions For + + Generating Backup. +

+
+
+

+ Enable the 'Automatic Database Backup' for the three scheduled actions. + Based on the setup, backups will be generated at daily, weekly, and + monthly intervals. +

+
+
+
+ +
+
+
+

+

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

+ Interactive User Interface.

+
+ +
+
+
+
+
+
+ +
+

+ Store Backup To Different + Locations.

+
+
+
+
+
+
+
+ +
+

+ Automatically Remove Old + Backups.

+
+
+

+ Effortlessly manage your storage + with automatic removal of old + backups, freeing up space while + keeping your most recent data + secure. +

+
+ +
+
+
+
+
+
+ +
+

+ Generate Database Backups on + regular intervals.

+
+
+

+ Protect your data with our + automated database backups, + ensuring regular, scheduled + backups for seamless recovery + and integrity.

+
+ +
+
+
+
+
+
+ +
+

+ Notify User On Success And + Failure Of Backup + Generation.

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

+ While configuring a + backup, selecting + the Zip option will + include the + filestore in the + backup, while + choosing the Dump + option will create a + backup without the + filestore. +

+
+
+ +
+ +
+

+ Enable the "Remove + Old Backups" option + in the backup + creation view to + automatically delete + previous backups + based on the number + of days specified. +

+
+
+ +
+ +
+

+ Enable the "Notify + User" option and + specify a contact to + receive an email + containing a + detailed report with + the failure reason + and backup details. + This option will + also send an email + upon successful + backup. +

+
+
+ +
+ +
+

+ Select the backup + destination as local + storage and specify + a backup path to a + location on the + system to create + backups on your own + system. +

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

+ Latest Release 19.0.1.0.0 +

+ + 19th September, 2025 + +
+
+
+
+
+ Add +
+
+
+
    +
  • + Initial Commit +
  • + +
+
+
+
+
+
+
+
+
+
+ + + +
+

+ Related Products +

+ +
+ + + +
+

+ Our Services

+ +
+ +
+
+ + + + + + diff --git a/auto_database_backup/views/db_backup_configure_views.xml b/auto_database_backup/views/db_backup_configure_views.xml new file mode 100755 index 000000000..85e3463a2 --- /dev/null +++ b/auto_database_backup/views/db_backup_configure_views.xml @@ -0,0 +1,313 @@ + + + + + db.backup.configure.view.search + db.backup.configure + + + + + + + + + + + + + + + + db.backup.configure.view.list + db.backup.configure + + + + + + + + + + + + + db.backup.configure.view.form + db.backup.configure + +
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + Refresh token set +
+
+ + No refresh token set +
+
+
+
+ +
+
+ +
+
+
+
+ + Refresh token set +
+
+ + No refresh token set +
+
+
+
+ +
+
+ +
+
+
+
+ + Refresh token set +
+
+ + No refresh token set +
+
+
+
+ +
+
+ +
+
+
+ + + + + + + + + +