Browse Source

Oct 30: [FIX] Bug Fixed 'auto_database_backup'

pull/346/head
Cybrosys Technologies 6 months ago
parent
commit
6111165f00
  1. 2
      auto_database_backup/__manifest__.py
  2. 27
      auto_database_backup/data/ir_cron_data.xml
  3. 6
      auto_database_backup/doc/RELEASE_NOTES.md
  4. 228
      auto_database_backup/models/db_backup_configure.py
  5. BIN
      auto_database_backup/static/description/assets/modules/1.gif
  6. BIN
      auto_database_backup/static/description/assets/modules/1.jpg
  7. BIN
      auto_database_backup/static/description/assets/modules/2.gif
  8. BIN
      auto_database_backup/static/description/assets/modules/2.jpg
  9. BIN
      auto_database_backup/static/description/assets/modules/3.jpg
  10. BIN
      auto_database_backup/static/description/assets/modules/3.png
  11. BIN
      auto_database_backup/static/description/assets/modules/4.png
  12. BIN
      auto_database_backup/static/description/assets/modules/5.jpg
  13. BIN
      auto_database_backup/static/description/assets/modules/5.png
  14. BIN
      auto_database_backup/static/description/assets/modules/6.gif
  15. BIN
      auto_database_backup/static/description/assets/modules/6.jpg
  16. BIN
      auto_database_backup/static/description/assets/screenshots/amazon10.png
  17. BIN
      auto_database_backup/static/description/assets/screenshots/backup_frequency.png
  18. BIN
      auto_database_backup/static/description/assets/screenshots/drop4.png
  19. BIN
      auto_database_backup/static/description/assets/screenshots/drop8.png
  20. BIN
      auto_database_backup/static/description/assets/screenshots/ftp.png
  21. BIN
      auto_database_backup/static/description/assets/screenshots/google 8.png
  22. BIN
      auto_database_backup/static/description/assets/screenshots/google6.png
  23. BIN
      auto_database_backup/static/description/assets/screenshots/google8.png
  24. BIN
      auto_database_backup/static/description/assets/screenshots/img.png
  25. BIN
      auto_database_backup/static/description/assets/screenshots/img_1.png
  26. BIN
      auto_database_backup/static/description/assets/screenshots/img_2.png
  27. BIN
      auto_database_backup/static/description/assets/screenshots/local.png
  28. BIN
      auto_database_backup/static/description/assets/screenshots/nextcloud1.png
  29. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive 4.png
  30. BIN
      auto_database_backup/static/description/assets/screenshots/remove.png
  31. BIN
      auto_database_backup/static/description/assets/screenshots/scheduled_action.png
  32. BIN
      auto_database_backup/static/description/assets/screenshots/scheduled_action_form.png
  33. BIN
      auto_database_backup/static/description/assets/screenshots/sftp.png
  34. 330
      auto_database_backup/static/description/index.html
  35. 6
      auto_database_backup/views/db_backup_configure_views.xml
  36. 3
      auto_database_backup/wizard/dropbox_auth_code.py

2
auto_database_backup/__manifest__.py

@ -22,7 +22,7 @@
{
'name': "Automatic Database Backup To Local Server, Remote Server,"
"Google Drive, Dropbox, Onedrive, Nextcloud and Amazon S3 Odoo18",
'version': '18.0.1.0.0',
'version': '18.0.2.0.0',
'live_test_url': 'https://youtu.be/Q2yMZyYjuTI',
'category': 'Extra Tools',
'summary': 'Odoo Database Backup, Automatic Backup, Database Backup, Automatic Backup,Database auto-backup, odoo backup'

27
auto_database_backup/data/ir_cron_data.xml

@ -1,14 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<!-- Schedule action for generating automatic database backup-->
<record id="ir_cron_auto_db_backup" model="ir.cron">
<field name="name">Backup : Automatic Database Backup</field>
<!-- Schedule action for generating automatic database backup-->
<record id="ir_cron_auto_db_backup_daily" model="ir.cron">
<field name="name">Backup : Daily Database Backup</field>
<field name="model_id" ref="model_db_backup_configure"/>
<field name="state">code</field>
<field name="code">model._schedule_auto_backup()</field>
<field name="code">model._schedule_auto_backup('daily')</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
</record>
<record id="ir_cron_auto_db_backup_weekly" model="ir.cron">
<field name="name">Backup : Weekly Database Backup</field>
<field name="model_id" ref="model_db_backup_configure"/>
<field name="state">code</field>
<field name="code">model._schedule_auto_backup('weekly')</field>
<field name="interval_number">1</field>
<field name="interval_type">weeks</field>
</record>
<record id="ir_cron_auto_db_backup_monthly" model="ir.cron">
<field name="name">Backup : Monthly Database Backup</field>
<field name="model_id" ref="model_db_backup_configure"/>
<field name="state">code</field>
<field name="code">model._schedule_auto_backup('monthly')</field>
<field name="interval_number">1</field>
<field name="interval_type">months</field>
</record>
</data>
</odoo>

6
auto_database_backup/doc/RELEASE_NOTES.md

@ -5,3 +5,9 @@
#### ADD
- Initial commit for Automatic Database Backup To Local Server, Remote Server, Google Drive, Dropbox, Onedrive, Nextcloud and Amazon S3 Odoo18.
#### 29.10.2024
#### Version 18.0.2.0.0
#### UPDT
- Added feature to set Multi-Level Backup Storage, Store backups in multiple locations based on different intervals.

228
auto_database_backup/models/db_backup_configure.py

@ -78,6 +78,11 @@ class DbBackupConfigure(models.Model):
('next_cloud', 'Next Cloud'),
('amazon_s3', 'Amazon S3')
], string='Backup Destination', help='Destination of the backup')
backup_frequency = fields.Selection([
('daily', 'Daily'),
('weekly', 'Weekly'),
('monthly', 'Monthly'),
], default='daily', string='Backup Frequency', help='Frequency of Backup Scheduling')
backup_path = fields.Char(string='Backup Path',
help='Local storage directory path')
sftp_host = fields.Char(string='SFTP Host', help='SFTP host details')
@ -215,8 +220,7 @@ class DbBackupConfigure(models.Model):
)
response = s3_client.head_bucket(Bucket=self.bucket_file_name)
if response['ResponseMetadata']['HTTPStatusCode'] == 200:
self.active = True
self.hide_active = True
self.active = self.hide_active = True
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
@ -232,8 +236,7 @@ class DbBackupConfigure(models.Model):
_("Bucket not found. Please check the bucket name and"
" try again."))
except Exception:
self.active = False
self.hide_active = False
self.active = self.hide_active = False
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
@ -255,11 +258,9 @@ class DbBackupConfigure(models.Model):
ncx = NextCloud(self.domain,
auth=HTTPBasicAuth(self.next_cloud_user_name,
self.next_cloud_password))
data = ncx.list_folders('/').__dict__
if data['raw'].status_code == 207:
self.active = True
self.hide_active = True
self.active = self.hide_active = True
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
@ -271,8 +272,7 @@ class DbBackupConfigure(models.Model):
}
}
else:
self.active = False
self.hide_active = False
self.active = self.hide_active = False
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
@ -285,8 +285,7 @@ class DbBackupConfigure(models.Model):
}
}
except Exception:
self.active = False
self.hide_active = False
self.active = self.hide_active = False
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
@ -303,10 +302,8 @@ class DbBackupConfigure(models.Model):
def _compute_redirect_uri(self):
"""Compute the redirect URI for onedrive and Google Drive"""
for rec in self:
base_url = request.env['ir.config_parameter'].get_param(
'web.base.url')
rec.onedrive_redirect_uri = base_url + '/onedrive/authentication'
rec.gdrive_redirect_uri = base_url + '/google_drive/authentication'
rec.onedrive_redirect_uri = self.get_base_url() + '/onedrive/authentication'
rec.gdrive_redirect_uri = self.get_base_url() + '/google_drive/authentication'
@api.depends('onedrive_access_token', 'onedrive_refresh_token')
def _compute_is_onedrive_token_generated(self):
@ -340,57 +337,50 @@ class DbBackupConfigure(models.Model):
}
def action_get_onedrive_auth_code(self):
"""Generate onedrive authorization code"""
AUTHORITY = \
'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
action = self.env["ir.actions.act_window"].sudo()._for_xml_id(
"auto_database_backup.db_backup_configure_action")
base_url = request.env['ir.config_parameter'].get_param('web.base.url')
url_return = base_url + \
'/web#id=%d&action=%d&view_type=form&model=%s' % (
self.id, action['id'], 'db.backup.configure')
"""Generate OneDrive authorization code."""
AUTHORITY = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
base_url = self.get_base_url()
action_id = self.env["ir.actions.act_window"].sudo()._for_xml_id(
"auto_database_backup.db_backup_configure_action")['id']
url_return = f"{base_url}/web#id={self.id}&action={action_id}&view_type=form&model=db.backup.configure"
state = {
'backup_config_id': self.id,
'url_return': url_return
}
encoded_params = urls.url_encode({
'url_return': url_return }
params = {
'response_type': 'code',
'client_id': self.onedrive_client_key,
'state': json.dumps(state),
'scope': ONEDRIVE_SCOPE,
'redirect_uri': base_url + '/onedrive/authentication',
'redirect_uri': f"{base_url}/onedrive/authentication",
'prompt': 'consent',
'access_type': 'offline'
})
auth_url = "%s?%s" % (AUTHORITY, encoded_params)
}
return {
'type': 'ir.actions.act_url',
'target': 'self',
'url': auth_url,
'url': f"{AUTHORITY}?{urls.url_encode(params)}",
}
def action_get_gdrive_auth_code(self):
"""Generate google drive authorization code"""
action = self.env["ir.actions.act_window"].sudo()._for_xml_id(
"auto_database_backup.db_backup_configure_action")
base_url = request.env['ir.config_parameter'].get_param('web.base.url')
url_return = base_url + \
'/web#id=%d&action=%d&view_type=form&model=%s' % (
self.id, action['id'], 'db.backup.configure')
"""Generate Google Drive authorization code."""
GOOGLE_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/auth"
base_url = self.get_base_url()
action_id = self.env["ir.actions.act_window"].sudo()._for_xml_id(
"auto_database_backup.db_backup_configure_action")['id']
url_return = f"{base_url}/web#id={self.id}&action={action_id}&view_type=form&model=db.backup.configure"
state = {
'backup_config_id': self.id,
'url_return': url_return
}
encoded_params = urls.url_encode({
'url_return': url_return }
params = {
'response_type': 'code',
'client_id': self.gdrive_client_key,
'scope': 'https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.file',
'redirect_uri': base_url + '/google_drive/authentication',
'redirect_uri': f"{base_url}/google_drive/authentication",
'access_type': 'offline',
'state': json.dumps(state),
'approval_prompt': 'force',
})
auth_url = "%s?%s" % (GOOGLE_AUTH_ENDPOINT, encoded_params)
}
auth_url = f"{GOOGLE_AUTH_ENDPOINT}?{urls.url_encode(params)}"
return {
'type': 'ir.actions.act_url',
'target': 'self',
@ -398,70 +388,64 @@ class DbBackupConfigure(models.Model):
}
def generate_onedrive_refresh_token(self):
"""Generate onedrive access token from refresh token if expired"""
base_url = request.env['ir.config_parameter'].get_param('web.base.url')
"""Generate OneDrive access token from refresh token if expired."""
base_url = self.get_base_url()
token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
headers = {"Content-type": "application/x-www-form-urlencoded"}
data = {
'client_id': self.onedrive_client_key,
'client_secret': self.onedrive_client_secret,
'scope': ONEDRIVE_SCOPE,
'grant_type': "refresh_token",
'redirect_uri': base_url + '/onedrive/authentication',
'refresh_token': self.onedrive_refresh_token
'redirect_uri': f"{base_url}/onedrive/authentication",
'refresh_token': self.onedrive_refresh_token,
}
try:
res = requests.post(
"https://login.microsoftonline.com/common/oauth2/v2.0/token",
data=data, headers=headers)
res = requests.post(token_url, data=data, headers=headers)
res.raise_for_status()
response = res.content and res.json() or {}
response = res.json() if res.ok else {}
if response:
expires_in = response.get('expires_in')
expires_in = response.get('expires_in', 0)
self.write({
'onedrive_access_token': response.get('access_token'),
'onedrive_refresh_token': response.get('refresh_token'),
'onedrive_token_validity': fields.Datetime.now() + timedelta(
seconds=expires_in) if expires_in else False,
'onedrive_token_validity': fields.Datetime.now() + timedelta(seconds=expires_in),
})
except requests.HTTPError as error:
_logger.exception("Bad microsoft onedrive request : %s !",
error.response.content)
_logger.exception("Bad Microsoft OneDrive request: %s", error.response.content)
raise error
def get_onedrive_tokens(self, authorize_code):
"""Generate onedrive tokens from authorization code."""
headers = {"content-type": "application/x-www-form-urlencoded"}
base_url = request.env['ir.config_parameter'].get_param('web.base.url')
"""Generate OneDrive tokens from authorization code."""
headers = {"Content-Type": "application/x-www-form-urlencoded"}
base_url = self.get_base_url()
data = {
'code': authorize_code,
'client_id': self.onedrive_client_key,
'client_secret': self.onedrive_client_secret,
'grant_type': 'authorization_code',
'scope': ONEDRIVE_SCOPE,
'redirect_uri': base_url + '/onedrive/authentication'
'redirect_uri': f"{base_url}/onedrive/authentication",
}
token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
try:
res = requests.post(
"https://login.microsoftonline.com/common/oauth2/v2.0/token",
data=data, headers=headers)
res = requests.post(token_url, data=data, headers=headers)
res.raise_for_status()
response = res.content and res.json() or {}
response = res.json() if res.ok else {}
if response:
expires_in = response.get('expires_in')
expires_in = response.get('expires_in', 0)
self.write({
'onedrive_access_token': response.get('access_token'),
'onedrive_refresh_token': response.get('refresh_token'),
'onedrive_token_validity': fields.Datetime.now() + timedelta(
seconds=expires_in) if expires_in else False,
'onedrive_token_validity': fields.Datetime.now() + timedelta(seconds=expires_in),
})
except requests.HTTPError as error:
_logger.exception("Bad microsoft onedrive request : %s !",
error.response.content)
_logger.exception("Bad Microsoft OneDrive request: %s", error.response.content)
raise error
def generate_gdrive_refresh_token(self):
"""Generate Google Drive access token from refresh token if expired"""
headers = {"content-type": "application/x-www-form-urlencoded"}
"""Generate Google Drive access token from refresh token if expired."""
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
'refresh_token': self.gdrive_refresh_token,
'client_id': self.gdrive_client_key,
@ -469,46 +453,44 @@ class DbBackupConfigure(models.Model):
'grant_type': 'refresh_token',
}
try:
res = requests.post(GOOGLE_TOKEN_ENDPOINT, data=data,
headers=headers)
res = requests.post(GOOGLE_TOKEN_ENDPOINT, data=data, headers=headers)
res.raise_for_status()
response = res.content and res.json() or {}
response = res.json() if res.ok else {}
if response:
expires_in = response.get('expires_in')
expires_in = response.get('expires_in', 0)
self.write({
'gdrive_access_token': response.get('access_token'),
'gdrive_token_validity': fields.Datetime.now() + timedelta(
seconds=expires_in) if expires_in else False,
'gdrive_token_validity': fields.Datetime.now() + timedelta(seconds=expires_in),
})
except requests.HTTPError as error:
error_key = error.response.json().get("error", "nc")
error_key = error.response.json().get("error", "unknown error")
error_msg = _(
"An error occurred while generating the token. Your"
"authorization code may be invalid or has already expired [%s]."
"You should check your Client ID and secret on the Google APIs"
" plateform or try to stop and restart your calendar"
" synchronisation.",
error_key)
"An error occurred while generating the token. Your "
"authorization code may be invalid or has already expired [%s]. "
"Please check your Client ID and secret on the Google APIs "
"platform or try stopping and restarting your calendar "
"synchronization.",
error_key
)
raise UserError(error_msg)
def get_gdrive_tokens(self, authorize_code):
"""Generate onedrive tokens from authorization code."""
"""Generate Google Drive tokens from authorization code."""
base_url = request.env['ir.config_parameter'].get_param('web.base.url')
headers = {"content-type": "application/x-www-form-urlencoded"}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
'code': authorize_code,
'client_id': self.gdrive_client_key,
'client_secret': self.gdrive_client_secret,
'grant_type': 'authorization_code',
'redirect_uri': base_url + '/google_drive/authentication'
'redirect_uri': f"{base_url}/google_drive/authentication",
}
try:
res = requests.post(GOOGLE_TOKEN_ENDPOINT, params=data,
headers=headers)
res = requests.post(GOOGLE_TOKEN_ENDPOINT, data=data, headers=headers)
res.raise_for_status()
response = res.content and res.json() or {}
response = res.json() if res.ok else {}
if response:
expires_in = response.get('expires_in')
expires_in = response.get('expires_in', 0)
self.write({
'gdrive_access_token': response.get('access_token'),
'gdrive_refresh_token': response.get('refresh_token'),
@ -517,8 +499,9 @@ class DbBackupConfigure(models.Model):
})
except requests.HTTPError:
error_msg = _(
"Something went wrong during your token generation. Maybe your"
" Authorization Code is invalid")
"Something went wrong during your token generation. "
"Your authorization code may be invalid."
)
raise UserError(error_msg)
def get_dropbox_auth_url(self):
@ -573,8 +556,7 @@ class DbBackupConfigure(models.Model):
ftp_server.quit()
except Exception as e:
raise UserError(_("FTP Exception: %s", e))
self.hide_active = True
self.active = True
self.active = self.hide_active = True
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
@ -596,20 +578,18 @@ class DbBackupConfigure(models.Model):
if self.backup_destination == 'local':
self.hide_active = True
def _schedule_auto_backup(self):
def _schedule_auto_backup(self, frequency):
"""Function for generating and storing backup.
Database backup for all the active records in backup configuration
model will be created."""
records = self.search([])
records = self.search([('backup_frequency', '=', frequency)])
mail_template_success = self.env.ref(
'auto_database_backup.mail_template_data_db_backup_successful')
mail_template_failed = self.env.ref(
'auto_database_backup.mail_template_data_db_backup_failed')
for rec in records:
backup_time = fields.datetime.utcnow().strftime(
"%Y-%m-%d_%H-%M-%S")
backup_filename = "%s_%s.%s" % (
rec.db_name, backup_time, rec.backup_format)
backup_time = fields.datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S")
backup_filename = f"{rec.db_name}_{backup_time}.{rec.backup_format}"
rec.backup_filename = backup_filename
# Local backup
if rec.backup_destination == 'local':
@ -619,7 +599,7 @@ class DbBackupConfigure(models.Model):
backup_file = os.path.join(rec.backup_path,
backup_filename)
f = open(backup_file, "wb")
self.dump_data(rec.db_name, f, rec.backup_format)
self.dump_data(rec.db_name, f, rec.backup_format, rec.backup_frequency)
f.close()
# Remove older backups
if rec.auto_remove:
@ -631,8 +611,7 @@ class DbBackupConfigure(models.Model):
if backup_duration.days >= rec.days_to_remove:
os.remove(file)
if rec.notify_user:
mail_template_success.send_mail(rec.id,
force_send=True)
mail_template_success.send_mail(rec.id, force_send=True)
except Exception as e:
rec.generated_exception = e
_logger.info('FTP Exception: %s', e)
@ -654,7 +633,7 @@ class DbBackupConfigure(models.Model):
ftp_server.cwd(rec.ftp_path)
with open(temp.name, "wb+") as tmp:
self.dump_data(rec.db_name, tmp,
rec.backup_format)
rec.backup_format, rec.backup_frequency)
ftp_server.storbinary('STOR %s' % backup_filename,
open(temp.name, "rb"))
if rec.auto_remove:
@ -689,7 +668,7 @@ class DbBackupConfigure(models.Model):
temp = tempfile.NamedTemporaryFile(
suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
self.dump_data(rec.db_name, tmp, rec.backup_format)
self.dump_data(rec.db_name, tmp, rec.backup_format, rec.backup_frequency)
try:
sftp.chdir(rec.sftp_path)
except IOError as e:
@ -726,7 +705,7 @@ class DbBackupConfigure(models.Model):
suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
self.dump_data(rec.db_name, tmp,
rec.backup_format)
rec.backup_format, rec.backup_frequency)
try:
headers = {
"Authorization": "Bearer %s" % rec.gdrive_access_token}
@ -749,8 +728,7 @@ class DbBackupConfigure(models.Model):
files_req = requests.get(
"https://www.googleapis.com/drive/v3/files?q=%s" % query,
headers=headers)
files = files_req.json()['files']
for file in files:
for file in files_req.json()['files']:
file_date_req = requests.get(
"https://www.googleapis.com/drive/v3/files/%s?fields=createdTime" %
file['id'], headers=headers)
@ -787,7 +765,7 @@ class DbBackupConfigure(models.Model):
suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
self.dump_data(rec.db_name, tmp,
rec.backup_format)
rec.backup_format, rec.backup_frequency)
try:
dbx = dropbox.Dropbox(
app_key=rec.dropbox_client_key,
@ -821,7 +799,7 @@ class DbBackupConfigure(models.Model):
temp = tempfile.NamedTemporaryFile(
suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
self.dump_data(rec.db_name, tmp, rec.backup_format)
self.dump_data(rec.db_name, tmp, rec.backup_format, rec.backup_frequency)
headers = {
'Authorization': 'Bearer %s' % rec.onedrive_access_token,
'Content-Type': 'application/json'}
@ -916,22 +894,22 @@ class DbBackupConfigure(models.Model):
suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
self.dump_data(rec.db_name, tmp,
rec.backup_format)
backup_file_path = temp.name
rec.backup_format, rec.backup_frequency)
backup_file_name = temp.name
remote_file_path = f"/{folder_name}/{rec.db_name}_" \
f"{backup_time}.{rec.backup_format}"
nc.put_file(remote_file_path, backup_file_path)
nc.put_file(remote_file_path, backup_file_name)
else:
# Dump the database to a temporary file
temp = tempfile.NamedTemporaryFile(
suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
self.dump_data(rec.db_name, tmp,
rec.backup_format)
backup_file_path = temp.name
rec.backup_format, rec.backup_frequency)
backup_file_name = temp.name
remote_file_path = f"/{folder_name}/{rec.db_name}_" \
f"{backup_time}.{rec.backup_format}"
nc.put_file(remote_file_path, backup_file_path)
nc.put_file(remote_file_path, backup_file_name)
except Exception:
raise ValidationError('Please check connection')
# Amazon S3 Backup
@ -981,19 +959,19 @@ class DbBackupConfigure(models.Model):
prefixes.add(prefix)
# If the specified folder is present in the bucket,
# take a backup of the database and upload it to the
# S3 bucket
# S3 bucket
if rec.aws_folder_name in prefixes:
temp = tempfile.NamedTemporaryFile(
suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
self.dump_data(rec.db_name, tmp,
rec.backup_format)
backup_file_path = temp.name
rec.backup_format, rec.backup_frequency)
backup_file_name = temp.name
remote_file_path = f"{rec.aws_folder_name}/{rec.db_name}_" \
f"{backup_time}.{rec.backup_format}"
s3.Object(rec.bucket_file_name,
remote_file_path).upload_file(
backup_file_path)
backup_file_name)
# If notify_user is enabled, send an email to the
# user notifying them about the successful backup
if rec.notify_user:
@ -1009,16 +987,14 @@ class DbBackupConfigure(models.Model):
if rec.notify_user:
mail_template_failed.send_mail(rec.id, force_send=True)
def dump_data(self, db_name, stream, backup_format):
def dump_data(self, db_name, stream, backup_format, backup_frequency):
"""Dump database `db` into file-like object `stream` if stream is None
return a file object with the dump. """
cron_user_id = self.env.ref('auto_database_backup.ir_cron_auto_db_backup').user_id.id
cron_user_id = self.env.ref(f'auto_database_backup.ir_cron_auto_db_backup_{backup_frequency}').user_id.id
if cron_user_id != self.env.user.id:
_logger.error(
'Unauthorized database operation. Backups should only be available from the cron job.')
raise ValidationError("Unauthorized database operation. Backups should only be available from the cron job.")
_logger.info('DUMP DB: %s format %s', db_name, backup_format)
cmd = [find_pg_tool('pg_dump'), '--no-owner', db_name]
env = exec_pg_environ()

BIN
auto_database_backup/static/description/assets/modules/1.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 KiB

BIN
auto_database_backup/static/description/assets/modules/1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 KiB

BIN
auto_database_backup/static/description/assets/modules/2.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

BIN
auto_database_backup/static/description/assets/modules/2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

BIN
auto_database_backup/static/description/assets/modules/3.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 KiB

BIN
auto_database_backup/static/description/assets/modules/3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

BIN
auto_database_backup/static/description/assets/modules/4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 92 KiB

BIN
auto_database_backup/static/description/assets/modules/5.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 KiB

BIN
auto_database_backup/static/description/assets/modules/5.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

BIN
auto_database_backup/static/description/assets/modules/6.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
auto_database_backup/static/description/assets/modules/6.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

BIN
auto_database_backup/static/description/assets/screenshots/amazon10.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 40 KiB

BIN
auto_database_backup/static/description/assets/screenshots/backup_frequency.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
auto_database_backup/static/description/assets/screenshots/drop4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 34 KiB

BIN
auto_database_backup/static/description/assets/screenshots/drop8.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 35 KiB

BIN
auto_database_backup/static/description/assets/screenshots/ftp.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 62 KiB

BIN
auto_database_backup/static/description/assets/screenshots/google 8.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 53 KiB

BIN
auto_database_backup/static/description/assets/screenshots/google6.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 53 KiB

BIN
auto_database_backup/static/description/assets/screenshots/google8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
auto_database_backup/static/description/assets/screenshots/img.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
auto_database_backup/static/description/assets/screenshots/img_1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
auto_database_backup/static/description/assets/screenshots/img_2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
auto_database_backup/static/description/assets/screenshots/local.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
auto_database_backup/static/description/assets/screenshots/nextcloud1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 44 KiB

BIN
auto_database_backup/static/description/assets/screenshots/onedrive 4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 51 KiB

BIN
auto_database_backup/static/description/assets/screenshots/remove.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
auto_database_backup/static/description/assets/screenshots/scheduled_action.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 178 KiB

BIN
auto_database_backup/static/description/assets/screenshots/scheduled_action_form.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 59 KiB

BIN
auto_database_backup/static/description/assets/screenshots/sftp.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 65 KiB

330
auto_database_backup/static/description/index.html

@ -68,6 +68,9 @@
border-radius: 20px;
width: 40px;
height: 40px;
Reaso: irfan ooked me ver
display: flex;
justify-content: center;
align-items: center;
@ -325,9 +328,7 @@
</div>
<div class="col-lg-4">
<div class="mb-4 d-flex flex-column justify-content-center gap-3"
style="border-radius: 12px;
border: 1px solid #B6BCCD;
background: #FFF;padding:32px ">
style="border-radius: 12px; border: 1px solid #B6BCCD; background: #FFF;padding:32px;">
<div class="d-flex justify-content-center align-items-center"
style="background-color:#7847D9; border-radius:8px !important; height:42px; width:42px">
<img src="./assets/icons/feature-icon.svg"
@ -344,11 +345,32 @@
S3, Google Drive, Dropbox, Onedrive.</p>
</div>
</div>
<div class="col-lg-4">
<div class="mb-4 d-flex flex-column justify-content-center gap-3"
style="border-radius: 12px;
border: 1px solid #B6BCCD;
background: #FFF;padding:32px; min-height: 236px; ">
<div class="d-flex justify-content-center align-items-center"
style="background-color:#7847D9; border-radius:8px !important; height:42px; width:42px">
<img src="./assets/icons/feature-icon.svg"
class="img-responsive" height="26px"
width="26px">
</div>
<h5 class="m-0"
style="color:#000 !important; font-weight:bold">
Multi-Level Backup Storage
</h5>
<p class="m-0"
style="font-size:0.9rem; color:#64728f; font-size: 16px; font-weight: 400;">
Store backups in multiple locations based on different intervals.</p>
</div>
</div>
</div>
</div>
<!--code -->
<div class="my-5">
<div class="position-relative" style=" padding: 5rem 4rem 5rem 4rem; background-color: #0A1425; border-radius: 12px;">
<div class="position-relative"
style=" padding: 5rem 4rem 5rem 4rem; background-color: #0A1425; border-radius: 12px;">
<div class="d-flex flex-column gap-4">
<span class="wrapper-subtitle"
style="font-size: 40px; font-weight: 700; color: #fff;line-height: 60px; text-transform: capitalize; width: 450px; font-family: Montserrat;">Automatic Database Backup</span>
@ -516,6 +538,36 @@
<div class="row">
<div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;">
<span style="color:#121212; font-size:calc(1.1rem + 1vw)">Backup</span>
<span style="color: #7f54b3; font-size:calc(1.1rem + 1vw)">Frequency</span>
</h1>
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Specify Backup
Destination and Frequency. Choose how often the backup should
run: daily, weekly, or monthly.
</p>
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/backup_frequency.png"
style="min-height: 1px;">
</div>
</div>
</div>
</div>
</div>
<div class="position-relative mb-4"
style="border-radius:10px; background-color:#f4f4f4">
<div class="p-md-5 p-3 position-relative">
<div class="row">
<div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;">
<span style="color:#121212; font-size:calc(1.1rem + 1vw)">Store Backup to Remote
</span>
@ -592,7 +644,12 @@
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
You'll need to create a new Google API project from <a href="https://console.cloud.google.com/"> Google Cloud console</a> and enabling the Google Drive API, Go to the Google API Console and log into your account. While creating the project, for the Redirect URI restrictions, copy your Odoo database URI followed by /google_drive/authentication. Example:
You'll need to create a new Google API project from <a
href="https://console.cloud.google.com/"> Google Cloud console</a>
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:
</p>
</div>
<div class="col-md-12 text-center">
@ -634,7 +691,8 @@
</div>
<div class="col-md-12 mb-4 p-3" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Create Credentials, Follow the steps, select Website application for the Application Type.
Create Credentials, Follow the steps, select Website application for the
Application Type.
</p>
</div>
<div class="col-md-12 text-center">
@ -648,7 +706,12 @@
</div>
<div class="col-md-12 mb-4 p-3" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Under the Authorized JavaScript Origins section, click + Add URI and type your company's Odoo URL address. Under the Authorized redirect URIs section, click + Add URI and type your company's Odoo URL address followed by /google_drive/authentication. After all the steps are completed, A Client ID and Client secret will be given, copy the credentials
Under the Authorized JavaScript Origins section, click + Add URI and
type your company's Odoo URL address. Under the Authorized redirect URIs
section, click + Add URI and type your company's Odoo URL address
followed by /google_drive/authentication. After all the steps are
completed, A Client ID and Client secret will be given, copy the
credentials
</p>
</div>
<div class="col-md-12 text-center">
@ -662,7 +725,9 @@
</div>
<div class="col-md-12 mb-4 p-3" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Configure Backup, Copy Client ID and Client Secret from Google Drive API Credentials page into their respective fields. Setup Token will redirect to an authorization page.
Configure Backup, Copy Client ID and Client Secret from Google Drive API
Credentials page into their respective fields. Setup Token will redirect
to an authorization page.
</p>
</div>
<div class="col-md-12 text-center">
@ -720,7 +785,9 @@
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
To get the app key and secret key go to the <a href="https://www.dropbox.com/developers" >App Console </a>. Create a new app
To get the app key and secret key go to the <a
href="https://www.dropbox.com/developers">App Console </a>. Create a
new app
</p>
</div>
<div class="col-md-12 text-center">
@ -734,7 +801,8 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Once you created the App , you can get the App key and App Secret as seen in the screenshot.
Once you created the App , you can get the App key and App Secret as
seen in the screenshot.
</p>
</div>
<div class="col-md-12 text-center">
@ -748,7 +816,8 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Choose your app's permission (files.content.write and files.content.read permissions required).then click on Submit
Choose your app's permission (files.content.write and files.content.read
permissions required).then click on Submit
</p>
</div>
<div class="col-md-12 text-center">
@ -762,7 +831,8 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Choose Dropbox as that of the backup destination. Enter the app secret and key and dropbox Folder. Click on the Setup Token
Choose Dropbox as that of the backup destination. Enter the app secret
and key and dropbox Folder. Click on the Setup Token
</p>
</div>
<div class="col-md-12 text-center">
@ -790,7 +860,7 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Reset the refresh token if required by clicking on the "Reset Token"
Reset the refresh token if required by clicking on the "Reset Token"
</p>
</div>
<div class="col-md-12 text-center">
@ -820,7 +890,11 @@
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Select Backup Destination as <a href="portal.azure.com">OneDrive.</a> Enter the App key and App secret. you'll need to register a new app in the Microsoft Azure portal. While registering the app for the Redirect URI restrictions, copy your Odoo database URI followed by /onedrive/authentication. Example:
Select Backup Destination as <a href="portal.azure.com">OneDrive.</a>
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:
</p>
</div>
<div class="col-md-12 text-center">
@ -834,7 +908,7 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Copy the Client ID and Generate Client Secret.
Copy the Client ID and Generate Client Secret.
</p>
</div>
<div class="col-md-12 text-center">
@ -931,7 +1005,8 @@
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
To Create an account in Nextcloud go to https://nextcloud.com/sign-up/, Enter Your Email Address and Sign up .
To Create an account in Nextcloud go to https://nextcloud.com/sign-up/,
Enter Your Email Address and Sign up .
</p>
</div>
<div class="col-md-12 text-center">
@ -945,7 +1020,8 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
You will be redirected to the page as shown in the screenshot, and it will ask you enter your email and password for the Nextcloud.
You will be redirected to the page as shown in the screenshot, and it
will ask you enter your email and password for the Nextcloud.
</p>
</div>
<div class="col-md-12 text-center">
@ -959,7 +1035,9 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
To get the Domain of the Nextcloud.Go to Settings in the Nextcloud and Click on Mobile & desktop. You will see server address Copy link and paste it in your Domain Name.
To get the Domain of the Nextcloud.Go to Settings in the Nextcloud and
Click on Mobile & desktop. You will see server address Copy link and
paste it in your Domain Name.
</p>
</div>
<div class="col-md-12 text-center">
@ -973,7 +1051,10 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Select the backup destination as Nextcloud. Enter the Domain Name, UserName, Password and Folder Name where you want to store your backup on the NextCloud server. Check the Connect button to check if the connection is successful.
Select the backup destination as Nextcloud. Enter the Domain Name,
UserName, Password and Folder Name where you want to store your backup
on the NextCloud server. Check the Connect button to check if the
connection is successful.
</p>
</div>
<div class="col-md-12 text-center">
@ -987,7 +1068,9 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Every day, a Scheduled Action will take place to store a backup on the Nextcloud Server. The backup will be stored as the folder name provided in the Folder ID field in Odoo.
Every day, a Scheduled Action will take place to store a backup on the
Nextcloud Server. The backup will be stored as the folder name provided
in the Folder ID field in Odoo.
</p>
</div>
<div class="col-md-12 text-center">
@ -1017,7 +1100,9 @@
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
To Create an account in Amazon S3 go to https://portal.aws.amazon.com/billing/signup#/start/email, Enter Your Email Address and Sign up .
To Create an account in Amazon S3 go to
https://portal.aws.amazon.com/billing/signup#/start/email, Enter Your
Email Address and Sign up .
</p>
</div>
<div class="col-md-12 text-center">
@ -1031,7 +1116,10 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
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. </p>
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. </p>
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
@ -1068,7 +1156,9 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Next You need to create a Bucket Folder in the Amazon S3.To do that Go the Services in the top right and go to Storage and S3 as shown in the Screen shot.
Next You need to create a Bucket Folder in the Amazon S3.To do that Go
the Services in the top right and go to Storage and S3 as shown in the
Screen shot.
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
@ -1081,7 +1171,7 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
To create Bucket folder,Click on the Create bucket Button.
To create Bucket folder,Click on the Create bucket Button.
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
@ -1094,7 +1184,9 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
On Creating a Bucket Folder,Check the rules for naming the Bucket folder,and Select the region as well.After that click on the create Bucket Button in the bottom of the page.
On Creating a Bucket Folder,Check the rules for naming the Bucket
folder,and Select the region as well.After that click on the create
Bucket Button in the bottom of the page.
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
@ -1107,7 +1199,7 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
You will see the Bucket Folder as shown in the screenshot.
You will see the Bucket Folder as shown in the screenshot.
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
@ -1120,7 +1212,11 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Select Backup Destination as Amazon S3. Enter the Amazon S3 Access Key,Amazon S3 Secret Key,Bucket Name->Bucket folder you have created in the Amazon S3 and the File Name->The Folder You want to store your backup in Amazon S3 Bucket Folder.Test connection button to check whether the connection is successful.
Select Backup Destination as Amazon S3. Enter the Amazon S3 Access
Key,Amazon S3 Secret Key,Bucket Name->Bucket folder you have created in
the Amazon S3 and the File Name->The Folder You want to store your
backup in Amazon S3 Bucket Folder.Test connection button to check
whether the connection is successful.
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
@ -1133,7 +1229,9 @@
</div>
<div class="col-md-12 mb-4" style="margin-top: 25px;">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
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. </div>
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.</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px">
@ -1189,7 +1287,9 @@
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Enable notify user option, and select a user to notify. An email notification will be sent to the selected user on backup successful and failure.
Enable notify user option, and select a user to notify. An email
notification will be sent to the selected user on backup successful and
failure.
</p>
</div>
<div class="col-md-12 text-center">
@ -1267,14 +1367,16 @@
<div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;">
<span style="color:#121212; font-size:calc(1.1rem + 1vw)">Scheduled Action For
<span style="color:#121212; font-size:calc(1.1rem + 1vw)">Scheduled Actions For
</span>
<span style="color: #7f54b3; font-size:calc(1.1rem + 1vw)">Generating Backup.</span>
</h1>
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:#64728f">
Enable the 'Automatic database Backup' scheduled action, and set up the execution interval. Based on the scheduled action setup, backups will be generated on regular intervals.
Enable the 'Automatic Database Backup' for the three scheduled actions.
Based on the setup, backups will be generated at daily, weekly, and
monthly intervals.
</p>
</div>
<div class="col-md-12 text-center">
@ -1304,7 +1406,6 @@
</div>
</div>
<div aria-labelledby="feature-tab"
class="tab-pane fade show py-1" id="feature"
@ -1626,84 +1727,111 @@
<!-- related post -->
<!-- -->
<section class="oe_container mt32">
<h2 style="color: #091E42;font-family: &quot;Montserrat&quot;;text-align: center;margin: 25px auto;text-transform: uppercase;" class="oe_slogan">
<b>Related Products</b>
</h2>
<div id="demo" class="row carousel slide mt64 mb32" data-bs-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/17.0/base_accounting_kit" target="_blank" style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;" class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;" src="./assets/modules/1.gif" />
<h4 class="mt0 text-truncate" style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Odoo 17 Full Accounting Kit</h4>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/17.0/ohrms_core" target="_blank" style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;" class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;" src="./assets/modules/2.gif" />
<h4 class="mt0 text-truncate" style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Open HRMS Core</h4>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/17.0/invoice_format_editor" target="_blank" style="color: #000; text-decoration: none;">
<div style="border-radius: 6px;padding: 16px; border: 1px solid #cbcbcb;" class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;" src="./assets/modules/3.png"/>
<h4 class="mt0 text-truncate" style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Odoo17 Invoice Format Editor </h4>
</div>
</a>
</div>
</div>
<div class="carousel-item">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/17.0/login_user_detail" target="_blank" style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;" class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;" src="./assets/modules/4.png" />
<h4 class="mt0 text-truncate" style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
User Log Details</h4>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/17.0/product_barcode" target="_blank" style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;" class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;" src="./assets/modules/5.png" />
<h4 class="mt0 text-truncate" style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Odoo17 Product Barcode Generator </h4>
</div>
</a>
<h2 style="color: #091E42;font-family: &quot;Montserrat&quot;;text-align: center;margin: 25px auto;text-transform: uppercase;"
class="oe_slogan">
<b>Related Products</b>
</h2>
<div id="demo" class="row carousel slide mt64 mb32" data-bs-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/18.0/base_accounting_kit"
target="_blank" style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;"
class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;"
src="./assets/modules/1.jpg"/>
<h4 class="mt0 text-truncate"
style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Odoo 18 Full Accounting Kit</h4>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/18.0/ohrms_core" target="_blank"
style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;"
class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;"
src="./assets/modules/2.jpg"/>
<h4 class="mt0 text-truncate"
style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Open HRMS Core</h4>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/18.0/woo_commerce"
target="_blank" style="color: #000; text-decoration: none;">
<div style="border-radius: 6px;padding: 16px; border: 1px solid #cbcbcb;"
class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;"
src="./assets/modules/3.jpg"/>
<h4 class="mt0 text-truncate"
style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Odoo WooCommerce Connector </h4>
</div>
</a>
</div>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/17.0/whatsapp_redirect" target="_blank" style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;" class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;" src="./assets/modules/6.jpg" />
<h4 class="mt0 text-truncate" style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Send Whatsapp Message Odoo17</h4>
</div>
</a>
<div class="carousel-item">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/18.0/dynamic_accounts_report" target="_blank"
style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;"
class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;"
src="./assets/modules/4.png"/>
<h4 class="mt0 text-truncate"
style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Odoo18 Dynamic Accounting Reports</h4>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/18.0/hide_menu_user" target="_blank"
style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;"
class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;"
src="./assets/modules/5.jpg"/>
<h4 class="mt0 text-truncate"
style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Hide Any Menu User Wise</h4>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left; padding: 10px;">
<a href="https://apps.odoo.com/apps/modules/18.0/odoo_dynamic_dashboard" target="_blank"
style="color: #000; text-decoration: none;">
<div style="border-radius: 6px; padding: 16px; border: 1px solid #cbcbcb;"
class="shadow-sm">
<img class="img img-responsive center-block" style=" max-width: 100%;"
src="./assets/modules/6.gif"/>
<h4 class="mt0 text-truncate"
style="text-align:center;width:100&#37; margin-bottom: 8px; font-weight: 600; padding-top: 16px; text-decoration:none;font-size: 18px; padding-bottom: 8px; margin-bottom: 0px">
Odoo Dynamic Dashboard</h4>
</div>
</a>
</div>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo" data-bs-slide="prev" style="margin-left: -30px;width: 35px;color: #000;">
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo" data-bs-slide="prev"
style="margin-left: -30px;width: 35px;color: #000;">
<span class="carousel-control-prev-icon">
<i class="fa fa-chevron-left" style="font-size:24px"></i>
</span>
</a>
<a class="carousel-control-next" href="#demo" data-bs-slide="next" style="margin-right: -30px;width: 35px;color: #000;">
</a>
<a class="carousel-control-next" href="#demo" data-bs-slide="next"
style="margin-right: -30px;width: 35px;color: #000;">
<span class="carousel-control-next-icon">
<i class="fa fa-chevron-right" style="font-size:24px"></i>
</span>
</a>
</div>
</section>
</a>
</div>
</section>
<!-- service-section -->
<section id="services" class="mt-5" style="border-radius: 16px;

6
auto_database_backup/views/db_backup_configure_views.xml

@ -1,14 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- Database backup configuration views-->
<record id="db_backup_configure_view_tree" model="ir.ui.view">
<field name="name">db.backup.configure.view.tree</field>
<record id="db_backup_configure_view_list" model="ir.ui.view">
<field name="name">db.backup.configure.view.list</field>
<field name="model">db.backup.configure</field>
<field name="arch" type="xml">
<list decoration-muted="(not active)">
<field name="name"/>
<field name="db_name"/>
<field name="backup_destination"/>
<field name="backup_frequency"/>
<field name="active"/>
</list>
</field>
@ -36,6 +37,7 @@
</group>
<group>
<field name="backup_destination" required="1"/>
<field name="backup_frequency" required="1"/>
<field name="backup_path"
invisible="backup_destination != 'local'"
required="backup_destination == 'local'"/>

3
auto_database_backup/wizard/dropbox_auth_code.py

@ -54,6 +54,5 @@ class AuthenticationWizard(models.TransientModel):
provided authorization code."""
backup_config = self.env['db.backup.configure'].browse(
self.env.context.get('active_id'))
backup_config.hide_active = True
backup_config.active = True
backup_config.active = backup_config.hide_active= True
backup_config.set_dropbox_refresh_token(self.dropbox_authorization_code)

Loading…
Cancel
Save