Browse Source

Nov 1 [ADD] Initial Commit 'auto_database_backup'

pull/221/merge
AjmalCybro 3 years ago
parent
commit
bb6c60d49d
  1. 43
      auto_database_backup/README.rst
  2. 25
      auto_database_backup/__init__.py
  3. 47
      auto_database_backup/__manifest__.py
  4. 21
      auto_database_backup/controllers/__init__.py
  5. 43
      auto_database_backup/controllers/main.py
  6. 182
      auto_database_backup/data/data.xml
  7. 6
      auto_database_backup/doc/RELEASE_NOTES.md
  8. 21
      auto_database_backup/models/__init__.py
  9. 590
      auto_database_backup/models/db_backup_configure.py
  10. 3
      auto_database_backup/security/ir.model.access.csv
  11. BIN
      auto_database_backup/static/description/assets/icons/check.png
  12. BIN
      auto_database_backup/static/description/assets/icons/chevron.png
  13. BIN
      auto_database_backup/static/description/assets/icons/cogs.png
  14. BIN
      auto_database_backup/static/description/assets/icons/consultation.png
  15. BIN
      auto_database_backup/static/description/assets/icons/ecom-black.png
  16. BIN
      auto_database_backup/static/description/assets/icons/education-black.png
  17. BIN
      auto_database_backup/static/description/assets/icons/hotel-black.png
  18. BIN
      auto_database_backup/static/description/assets/icons/license.png
  19. BIN
      auto_database_backup/static/description/assets/icons/lifebuoy.png
  20. BIN
      auto_database_backup/static/description/assets/icons/manufacturing-black.png
  21. BIN
      auto_database_backup/static/description/assets/icons/pos-black.png
  22. BIN
      auto_database_backup/static/description/assets/icons/puzzle.png
  23. BIN
      auto_database_backup/static/description/assets/icons/restaurant-black.png
  24. BIN
      auto_database_backup/static/description/assets/icons/service-black.png
  25. BIN
      auto_database_backup/static/description/assets/icons/trading-black.png
  26. BIN
      auto_database_backup/static/description/assets/icons/training.png
  27. BIN
      auto_database_backup/static/description/assets/icons/update.png
  28. BIN
      auto_database_backup/static/description/assets/icons/user.png
  29. BIN
      auto_database_backup/static/description/assets/icons/wrench.png
  30. BIN
      auto_database_backup/static/description/assets/misc/categories.png
  31. BIN
      auto_database_backup/static/description/assets/misc/check-box.png
  32. BIN
      auto_database_backup/static/description/assets/misc/compass.png
  33. BIN
      auto_database_backup/static/description/assets/misc/corporate.png
  34. BIN
      auto_database_backup/static/description/assets/misc/customer-support.png
  35. BIN
      auto_database_backup/static/description/assets/misc/cybrosys-logo.png
  36. BIN
      auto_database_backup/static/description/assets/misc/features.png
  37. BIN
      auto_database_backup/static/description/assets/misc/logo.png
  38. BIN
      auto_database_backup/static/description/assets/misc/pictures.png
  39. BIN
      auto_database_backup/static/description/assets/misc/pie-chart.png
  40. BIN
      auto_database_backup/static/description/assets/misc/right-arrow.png
  41. BIN
      auto_database_backup/static/description/assets/misc/star.png
  42. BIN
      auto_database_backup/static/description/assets/misc/support.png
  43. BIN
      auto_database_backup/static/description/assets/misc/whatsapp.png
  44. BIN
      auto_database_backup/static/description/assets/modules/1.png
  45. BIN
      auto_database_backup/static/description/assets/modules/2.png
  46. BIN
      auto_database_backup/static/description/assets/modules/3.png
  47. BIN
      auto_database_backup/static/description/assets/modules/4.png
  48. BIN
      auto_database_backup/static/description/assets/modules/5.gif
  49. BIN
      auto_database_backup/static/description/assets/modules/6.png
  50. BIN
      auto_database_backup/static/description/assets/screenshots/backup1.png
  51. BIN
      auto_database_backup/static/description/assets/screenshots/backup10.png
  52. BIN
      auto_database_backup/static/description/assets/screenshots/backup11.png
  53. BIN
      auto_database_backup/static/description/assets/screenshots/backup12.png
  54. BIN
      auto_database_backup/static/description/assets/screenshots/backup13.png
  55. BIN
      auto_database_backup/static/description/assets/screenshots/backup14.png
  56. BIN
      auto_database_backup/static/description/assets/screenshots/backup15.png
  57. BIN
      auto_database_backup/static/description/assets/screenshots/backup16.png
  58. BIN
      auto_database_backup/static/description/assets/screenshots/backup17.png
  59. BIN
      auto_database_backup/static/description/assets/screenshots/backup18.png
  60. BIN
      auto_database_backup/static/description/assets/screenshots/backup2.png
  61. BIN
      auto_database_backup/static/description/assets/screenshots/backup3.png
  62. BIN
      auto_database_backup/static/description/assets/screenshots/backup4.png
  63. BIN
      auto_database_backup/static/description/assets/screenshots/backup5.png
  64. BIN
      auto_database_backup/static/description/assets/screenshots/backup6.png
  65. BIN
      auto_database_backup/static/description/assets/screenshots/backup7.png
  66. BIN
      auto_database_backup/static/description/assets/screenshots/backup8.png
  67. BIN
      auto_database_backup/static/description/assets/screenshots/backup9.png
  68. BIN
      auto_database_backup/static/description/assets/screenshots/drive1.png
  69. BIN
      auto_database_backup/static/description/assets/screenshots/drive2.png
  70. BIN
      auto_database_backup/static/description/assets/screenshots/drive3.png
  71. BIN
      auto_database_backup/static/description/assets/screenshots/drive4.png
  72. BIN
      auto_database_backup/static/description/assets/screenshots/drive5.png
  73. BIN
      auto_database_backup/static/description/assets/screenshots/hero.png
  74. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive1.png
  75. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive2.png
  76. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive3.png
  77. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive4.png
  78. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive5.png
  79. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive6.png
  80. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive7.png
  81. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive8.png
  82. BIN
      auto_database_backup/static/description/assets/screenshots/onedrive9.png
  83. BIN
      auto_database_backup/static/description/banner.png
  84. BIN
      auto_database_backup/static/description/icon.png
  85. 724
      auto_database_backup/static/description/index.html
  86. 212
      auto_database_backup/views/db_backup_configure_views.xml
  87. 23
      auto_database_backup/wizard/__init__.py
  88. 48
      auto_database_backup/wizard/auth_code_wizard.py
  89. 27
      auto_database_backup/wizard/authentication_wizard_views.xml

43
auto_database_backup/README.rst

@ -0,0 +1,43 @@
Automatic Database Backup To Local Server, Remote Server, Google Drive And Dropbox
==================================================================================
* Generate Database Backups and store to multiple locations
Installation
============
- www.odoo.com/documentation/16.0/setup/install.html
- Install our custom addon
License
-------
General Public License, Version 3 (LGPL v3).
(https://www.odoo.com/documentation/user/16.0/legal/licenses/licenses.html)
Company
-------
* 'Cybrosys Techno Solutions <https://cybrosys.com/>`__
Credits
-------
* Developer:
(v15) Midilaj @ Cybrosys
(v16) Midilaj @ Cybrosys
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
==========
This module is maintained by Cybrosys Technologies.
For support and more information, please visit https://www.cybrosys.com
Further information
===================
HTML Description: `<static/description/index.html>`__

25
auto_database_backup/__init__.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import models
from . import wizard
from . import controllers

47
auto_database_backup/__manifest__.py

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
{
'name': "Automatic Database Backup To Local Server, Remote Server, Google Drive, Dropbox and Onedrive",
'version': '16.0.1.0.0',
'summary': """Generate automatic backup of databases and store to local, google drive, dropbox, onedrive or remote server""",
'description': """This module has been developed for creating database backups automatically
and store it to the different locations.""",
'author': "Cybrosys Techno Solutions",
'website': "https://www.cybrosys.com",
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'category': 'Tools',
'depends': ['base', 'mail'],
'data': [
'security/ir.model.access.csv',
'data/data.xml',
'views/db_backup_configure_views.xml',
'wizard/authentication_wizard_views.xml',
],
'external_dependencies': {'python': ['dropbox']},
'license': 'LGPL-3',
'images': ['static/description/banner.png'],
'installable': True,
'auto_install': False,
'application': False,
}

21
auto_database_backup/controllers/__init__.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
from . import main

43
auto_database_backup/controllers/main.py

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
import json
from odoo import http
from odoo.http import request
class OnedriveAuth(http.Controller):
@http.route('/onedrive/authentication', type='http', auth="public")
def oauth2callback(self, **kw):
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'))
url_return = state.get('url_return')
return request.redirect(url_return)
@http.route('/google_drive/authentication', type='http', auth="public")
def gdrive_oauth2callback(self, **kw):
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'))
url_return = state.get('url_return')
return request.redirect(url_return)

182
auto_database_backup/data/data.xml

@ -0,0 +1,182 @@
<?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>
<field name="model_id" ref="model_db_backup_configure"/>
<field name="state">code</field>
<field name="code">model._schedule_auto_backup()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active">False</field>
</record>
</data>
<data>
<!-- Database backup operation Successful email template-->
<record id="mail_template_data_db_backup_successful" model="mail.template">
<field name="name">Database Backup: Notification Successful</field>
<field name="model_id" ref="auto_database_backup.model_db_backup_configure"/>
<field name="subject">Database Backup Successful: {{ object.db_name }}</field>
<field name="email_to">{{ object.user_id.email_formatted }}</field>
<field name="body_html" type="html">
<div style="margin: 0px; padding: 0px;">
<p style="margin: 0px;">
<span>Dear <t t-out="object.user_id.name"/>,
</span>
<br/>
<br/>
<span style="margin-top: 8px;">Backup of the database
<i>
<t t-out="object.db_name"/>
</i>
has been successfully generated and stored to
<t t-if="object.backup_destination == 'local'">
<i>Local</i>
</t>
<t t-elif="object.backup_destination == 'google_drive'">
<i>Google Drive</i>
</t>
<t t-elif="object.backup_destination == 'ftp'">
<i>FTP Server</i>
</t>
<t t-elif="object.backup_destination == 'sftp'">
<i>SFTP Server</i>
</t>
<t t-elif="object.backup_destination == 'dropbox'">
<i>Dropbox</i>
</t>
<t t-elif="object.backup_destination == 'onedrive'">
<i>Onedrive</i>
</t>
.
<br/>
<br/>
Database Name:
<t t-out="object.db_name"/>
<br/>
Destination:
<t t-if="object.backup_destination == 'local'">
Local
</t>
<t t-elif="object.backup_destination == 'google_drive'">
Google Drive
</t>
<t t-elif="object.backup_destination == 'ftp'">
FTP Server
</t>
<t t-elif="object.backup_destination == 'sftp'">
SFTP Server
</t>
<t t-elif="object.backup_destination == 'dropbox'">
Dropbox
</t>
<t t-elif="object.backup_destination == 'onedrive'">
Onedrive
</t>
<t t-if="object.backup_destination in ('local', 'ftp', 'sftp', 'dropbox')">
<br/>
Backup Path:
<t t-if="object.backup_destination == 'local'">
<t t-out="object.backup_path"/>
</t>
<t t-elif="object.backup_destination == 'ftp'">
<t t-out="object.ftp_path"/>
</t>
<t t-elif="object.backup_destination == 'sftp'">
<t t-out="object.sftp_path"/>
</t>
<t t-elif="object.backup_destination == 'dropbox'">
<t t-out="object.dropbox_folder"/>
</t>
</t>
<br/>
Backup Type:
<t t-out="object.backup_format"/>
<br/>
Backup FileName:
<t t-out="object.backup_filename"/>
</span>
</p>
</div>
</field>
</record>
<!-- Database backup operation failed email templated-->
<record id="mail_template_data_db_backup_failed" model="mail.template">
<field name="name">Database Backup: Notification Failed</field>
<field name="model_id" ref="auto_database_backup.model_db_backup_configure"/>
<field name="subject">Database Backup Failed: {{ object.db_name }}</field>
<field name="email_to">{{ object.user_id.email_formatted }}</field>
<field name="body_html" type="html">
<div style="margin: 0px; padding: 0px;">
<p style="margin: 0px;">
<span>Dear <t t-out="object.user_id.name"/>,
</span>
<br/>
<br/>
<span style="margin-top: 8px;">Backup generation of the database
<i>
<t t-out="object.db_name"/>
</i>
has been Failed.
<br/>
<br/>
Database Name: <t t-out="object.db_name"/>
<br/>
Destination:
<t t-if="object.backup_destination == 'local'">
Local
</t>
<t t-elif="object.backup_destination == 'google_drive'">
Google Drive
</t>
<t t-elif="object.backup_destination == 'ftp'">
FTP Server
</t>
<t t-elif="object.backup_destination == 'sftp'">
SFTP Server
</t>
<t t-elif="object.backup_destination == 'dropbox'">
Dropbox
</t>
<t t-elif="object.backup_destination == 'onedrive'">
Onedrive
</t>
<t t-if="object.backup_destination in ('local', 'ftp', 'sftp', 'dropbox')">
<br/>
Backup Path:
<t t-if="object.backup_destination == 'local'">
<t t-out="object.backup_path"/>
</t>
<t t-elif="object.backup_destination == 'ftp'">
<t t-out="object.ftp_path"/>
</t>
<t t-elif="object.backup_destination == 'sftp'">
<t t-out="object.sftp_path"/>
</t>
<t t-elif="object.backup_destination == 'dropbox'">
<t t-out="object.dropbox_folder"/>
</t>
</t>
<br/>
Backup Type: <t t-out="object.backup_format"/>
<br/>
<br/>
<b>Error Message:</b>
<br/>
<i><t t-out="object.generated_exception"/></i>
</span>
</p>
</div>
</field>
</record>
</data>
</odoo>

6
auto_database_backup/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <auto_database_backup>
#### 31.10.2022
#### Version 16.0.1.0.0
#### ADD
- Initial commit for auto_database_backup

21
auto_database_backup/models/__init__.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
from . import db_backup_configure

590
auto_database_backup/models/db_backup_configure.py

@ -0,0 +1,590 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
import odoo
from odoo.service import db
from odoo.http import request
import dropbox
from werkzeug import urls
from datetime import timedelta
import datetime
import os
import paramiko
import ftplib
import json
import requests
import tempfile
import errno
import logging
_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 AutoDatabaseBackup(models.Model):
_name = 'db.backup.configure'
_description = 'Automatic Database Backup'
name = fields.Char(string='Name', required=True)
db_name = fields.Char(string='Database Name', required=True)
master_pwd = fields.Char(string='Master Password', required=True)
backup_format = fields.Selection([
('zip', 'Zip'),
('dump', 'Dump')
], string='Backup Format', default='zip', required=True)
backup_destination = fields.Selection([
('local', 'Local Storage'),
('google_drive', 'Google Drive'),
('ftp', 'FTP'),
('sftp', 'SFTP'),
('dropbox', 'Dropbox'),
('onedrive', 'Onedrive')
], string='Backup Destination')
backup_path = fields.Char(string='Backup Path', help='Local storage directory path')
sftp_host = fields.Char(string='SFTP Host')
sftp_port = fields.Char(string='SFTP Port', default=22)
sftp_user = fields.Char(string='SFTP User', copy=False)
sftp_password = fields.Char(string='SFTP Password', copy=False)
sftp_path = fields.Char(string='SFTP Path')
ftp_host = fields.Char(string='FTP Host')
ftp_port = fields.Char(string='FTP Port', default=21)
ftp_user = fields.Char(string='FTP User', copy=False)
ftp_password = fields.Char(string='FTP Password', copy=False)
ftp_path = fields.Char(string='FTP Path')
dropbox_client_id = fields.Char(string='Dropbox Client ID', copy=False)
dropbox_client_secret = fields.Char(string='Dropbox Client Secret', copy=False)
dropbox_refresh_token = fields.Char(string='Dropbox Refresh Token', copy=False)
is_dropbox_token_generated = fields.Boolean(string='Dropbox Token Generated', compute='_compute_is_dropbox_token_generated', copy=False)
dropbox_folder = fields.Char('Dropbox Folder')
active = fields.Boolean(default=True)
auto_remove = fields.Boolean(string='Remove Old Backups')
days_to_remove = fields.Integer(string='Remove After',
help='Automatically delete stored backups after this specified number of days')
google_drive_folderid = fields.Char(string='Drive Folder ID')
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')
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_id = fields.Char(string='Onedrive Client ID', copy=False)
onedrive_client_secret = fields.Char(string='Onedrive Client Secret', copy=False)
onedrive_access_token = fields.Char(string='Onedrive Access Token', copy=False)
onedrive_refresh_token = fields.Char(string='Onedrive Refresh Token', copy=False)
onedrive_token_validity = fields.Datetime(string='Onedrive Token Validity', copy=False)
onedrive_folder_id = fields.Char(string='Folder ID')
is_onedrive_token_generated = fields.Boolean(string='onedrive Tokens Generated',
compute='_compute_is_onedrive_token_generated', copy=False)
gdrive_refresh_token = fields.Char(string='Google drive Refresh Token', copy=False)
gdrive_access_token = fields.Char(string='Google Drive Access Token', copy=False)
is_google_drive_token_generated = fields.Boolean(string='Google drive Token Generated',
compute='_compute_is_google_drive_token_generated', copy=False)
gdrive_client_id = fields.Char(string='Google Drive Client ID', copy=False)
gdrive_client_secret = fields.Char(string='Google Drive Client Secret', copy=False)
gdrive_token_validity = fields.Datetime(string='Google Drive Token Validity', copy=False)
onedrive_redirect_uri = fields.Char(string='Onedrive Redirect URI', compute='_compute_redirect_uri')
gdrive_redirect_uri = fields.Char(string='Google Drive Redirect URI', compute='_compute_redirect_uri')
def _compute_redirect_uri(self):
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'
@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 wizard to set up dropbox Authorization code
"""
return {
'type': 'ir.actions.act_window',
'name': 'Dropbox Authorization Wizard',
'res_model': 'authentication.wizard',
'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'
action = self.env["ir.actions.act_window"].sudo()._for_xml_id("auto_database_backup.action_db_backup_configure")
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')
state = {
'backup_config_id': self.id,
'url_return': url_return
}
encoded_params = urls.url_encode({
'response_type': 'code',
'client_id': self.onedrive_client_id,
'state': json.dumps(state),
'scope': ONEDRIVE_SCOPE,
'redirect_uri': 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,
}
def action_get_gdrive_auth_code(self):
"""
Generate ogoogle drive authorization code
"""
action = self.env["ir.actions.act_window"].sudo()._for_xml_id("auto_database_backup.action_db_backup_configure")
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')
state = {
'backup_config_id': self.id,
'url_return': url_return
}
encoded_params = urls.url_encode({
'response_type': 'code',
'client_id': self.gdrive_client_id,
'scope': 'https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.file',
'redirect_uri': base_url + '/google_drive/authentication',
'access_type': 'offline',
'state': json.dumps(state),
'approval_prompt': 'force',
})
auth_url = "%s?%s" % (GOOGLE_AUTH_ENDPOINT, encoded_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 = request.env['ir.config_parameter'].get_param('web.base.url')
headers = {"Content-type": "application/x-www-form-urlencoded"}
data = {
'client_id': self.onedrive_client_id,
'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
}
try:
res = requests.post("https://login.microsoftonline.com/common/oauth2/v2.0/token", data=data, headers=headers)
res.raise_for_status()
response = res.content and res.json() or {}
if response:
expires_in = response.get('expires_in')
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,
})
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 = request.env['ir.config_parameter'].get_param('web.base.url')
data = {
'code': authorize_code,
'client_id': self.onedrive_client_id,
'client_secret': self.onedrive_client_secret,
'grant_type': 'authorization_code',
'scope': ONEDRIVE_SCOPE,
'redirect_uri': base_url + '/onedrive/authentication'
}
try:
res = requests.post("https://login.microsoftonline.com/common/oauth2/v2.0/token", data=data, headers=headers)
res.raise_for_status()
response = res.content and res.json() or {}
if response:
expires_in = response.get('expires_in')
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,
})
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_id,
'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.content and res.json() or {}
if response:
expires_in = response.get('expires_in')
self.write({
'gdrive_access_token': response.get('access_token'),
'gdrive_token_validity': fields.Datetime.now() + timedelta(seconds=expires_in) if expires_in else False,
})
except requests.HTTPError as error:
error_key = error.response.json().get("error", "nc")
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)
raise UserError(error_msg)
def get_gdrive_tokens(self, authorize_code):
"""
Generate onedrive 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_id,
'client_secret': self.gdrive_client_secret,
'grant_type': 'authorization_code',
'redirect_uri': base_url + '/google_drive/authentication'
}
try:
res = requests.post(GOOGLE_TOKEN_ENDPOINT, params=data,
headers=headers)
res.raise_for_status()
response = res.content and res.json() or {}
if response:
expires_in = response.get('expires_in')
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. Maybe your Authorization Code is invalid")
raise UserError(error_msg)
def get_dropbox_auth_url(self):
"""
Return dropbox authorization url
"""
dbx_auth = dropbox.oauth.DropboxOAuth2FlowNoRedirect(self.dropbox_client_id, self.dropbox_client_secret,
token_access_type='offline')
auth_url = dbx_auth.start()
return auth_url
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_id, 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()
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 test_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))
title = _("Connection Test Succeeded!")
message = _("Everything seems properly set up!")
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': title,
'message': message,
'sticky': False,
}
}
def _schedule_auto_backup(self):
"""
Function for generating and storing backup
Database backup for all the active records in backup configuration model will be created
"""
records = self.search([])
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.datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S")
backup_filename = "%s_%s.%s" % (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")
odoo.service.db.dump_db(rec.db_name, f, rec.backup_format)
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.datetime.fromtimestamp(os.path.getctime(file))
backup_duration = datetime.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:
odoo.service.db.dump_db(rec.db_name, tmp, rec.backup_format)
ftp_server.storbinary('STOR %s' % backup_filename, open(temp.name, "rb"))
if rec.auto_remove:
files = ftp_server.nlst()
for f in files:
create_time = datetime.datetime.strptime(ftp_server.sendcmd('MDTM ' + f)[4:], "%Y%m%d%H%M%S")
diff_days = (datetime.datetime.now() - create_time).days
if diff_days >= rec.days_to_remove:
ftp_server.delete(f)
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:
odoo.service.db.dump_db(rec.db_name, tmp, rec.backup_format)
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: (datetime.datetime.now() - datetime.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':
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:
odoo.service.db.dump_db(rec.db_name, tmp, rec.backup_format)
try:
# access_token = self.env['google.drive.config'].sudo().get_access_token()
headers = {"Authorization": "Bearer %s" % rec.gdrive_access_token}
para = {
"name": backup_filename,
"parents": [rec.google_drive_folderid],
}
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_folderid
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:
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 = (datetime.datetime.now() - datetime.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)
# Dropbox backup
elif rec.backup_destination == 'dropbox':
temp = tempfile.NamedTemporaryFile(suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
odoo.service.db.dump_db(rec.db_name, tmp, rec.backup_format)
try:
dbx = dropbox.Dropbox(app_key=rec.dropbox_client_id, 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: (datetime.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':
if rec.onedrive_token_validity <= fields.Datetime.now():
rec.generate_onedrive_refresh_token()
temp = tempfile.NamedTemporaryFile(suffix='.%s' % rec.backup_format)
with open(temp.name, "wb+") as tmp:
odoo.service.db.dump_db(rec.db_name, tmp, rec.backup_format)
headers = {'Authorization': 'Bearer %s' % rec.onedrive_access_token, 'Content-Type': 'application/json'}
upload_session_url = MICROSOFT_GRAPH_END_POINT + "/v1.0/me/drive/items/%s:/%s:/createUploadSession" % (rec.onedrive_folder_id, backup_filename)
try:
upload_session = requests.post(upload_session_url, headers=headers)
upload_url = upload_session.json().get('uploadUrl')
requests.put(upload_url, data=temp.read())
if rec.auto_remove:
list_url = MICROSOFT_GRAPH_END_POINT + "/v1.0/me/drive/items/%s/children" % rec.onedrive_folder_id
response = requests.get(list_url, headers=headers)
files = response.json().get('value')
for file in files:
create_time = file['createdDateTime'][:19].replace('T', ' ')
diff_days = (datetime.datetime.now() - datetime.datetime.strptime(create_time, '%Y-%m-%d %H:%M:%S')).days
if diff_days >= rec.days_to_remove:
delete_url = MICROSOFT_GRAPH_END_POINT + "/v1.0/me/drive/items/%s" % file['id']
requests.delete(delete_url, headers=headers)
if rec.notify_user:
mail_template_success.send_mail(rec.id, force_send=True)
except Exception as error:
rec.generated_exception = error
_logger.info('Onedrive Exception: %s', error)
if rec.notify_user:
mail_template_failed.send_mail(rec.id, force_send=True)

3
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,access.db.backup.configure,model_db_backup_configure,base.group_user,1,1,1,1
access_authentication_wizard,access.authentication.wizard,model_authentication_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_db_backup_configure access.db.backup.configure model_db_backup_configure base.group_user 1 1 1 1
3 access_authentication_wizard access.authentication.wizard model_authentication_wizard base.group_user 1 1 1 1

BIN
auto_database_backup/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
auto_database_backup/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
auto_database_backup/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
auto_database_backup/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
auto_database_backup/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
auto_database_backup/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
auto_database_backup/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
auto_database_backup/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
auto_database_backup/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
auto_database_backup/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
auto_database_backup/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
auto_database_backup/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
auto_database_backup/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
auto_database_backup/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
auto_database_backup/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
auto_database_backup/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
auto_database_backup/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
auto_database_backup/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
auto_database_backup/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
auto_database_backup/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
auto_database_backup/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
auto_database_backup/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
auto_database_backup/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
auto_database_backup/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
auto_database_backup/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
auto_database_backup/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
auto_database_backup/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
auto_database_backup/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
auto_database_backup/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
auto_database_backup/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
auto_database_backup/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
auto_database_backup/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
auto_database_backup/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
auto_database_backup/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
auto_database_backup/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

724
auto_database_backup/static/description/index.html

@ -0,0 +1,724 @@
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex justify-content-between align-items-center"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" style="width: 42px; height: 42px;" />
<div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<!-- APP HERO -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Automatic
Database Backup</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">Automatic Database Backup To
Local
Server, Remote Server, Google Drive, Onedrive And Dropbox.</p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.png" class="img-responsive"
style="width: 100%; margin-left: auto; margin-right: auto;" />
</div>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Overview
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
This module helps to generate backups of your databases automatically on regular interval of times.
The generated backups can be stored into local storage, ftp server, sftp server, dropbox, Google Drive or
Onedrive.
User can enable auto remove option to automatically delete old backups.
User can enable email notification to be notified about the success and failure of the backup generation
and storage.
Using Automatic Database Backup module user can generate and store database backups to multiple
location.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Features
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center" style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Generate Database
Backups on regular intervals</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Store Backup to
Dropbox</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Store Backup to
Onedrive</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Notify user on success
and failure of backup generation</span>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Store Backup to Remote
Server</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Generated backup can be
stored to Google Drive</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Automatically remove
old backups</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Database Backup
Configuration Menu</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Got Setting --> Technical --> Backup Configuration to configure backups</p>
<img src="assets/screenshots/backup1.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Crate New Database Backup
Configuration</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Enter the database name and master password. specify backup type and destination.
Enter the backup directory path, if directory does not exist new directory will be created.</p>
<img src="assets/screenshots/backup2.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Store Backup to Remote
SFTP Server</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Select backup destination as SFTP, enter credentials.
Test connection button to check whether the connection is successful.
</p>
<img src="assets/screenshots/backup3.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Store Backup to Remote
FTP Server</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Select backup destination
as FTP, enter credentials.
Test connection button to check whether the connection is successful.</p>
<img src="assets/screenshots/backup4.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Store Backup to Google
Drive</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">you'll need to create a new
Google API project and enabling the Google Drive API, Go to the <a href="https://console.developers.google.com/"
target="_blank">Google API Console</a> 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>
<img src="assets/screenshots/drive1.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Enable Google Drive API</p>
<img src="assets/screenshots/drive2.png" class="img-thumbnail">
<img src="assets/screenshots/drive3.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Create Credentials, Follow
the steps, select Website application for the Application Type.</p>
<img src="assets/screenshots/drive4.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">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 <i>/google_drive/authentication</i>.
After all the steps are completed, A client ID and Secret will be given, copy the credentials
</p>
<img src="assets/screenshots/drive5.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Configure Backup, Copy
Client ID and Client Secret from Google Drive API Credentials page into their respective fields.</p>
<img src="assets/screenshots/backup5.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Setup Tokens, it will be
redirected to an authorization page.</p>
<img src="assets/screenshots/backup6.png" class="img-thumbnail">
<img src="assets/screenshots/backup7.png" class="img-thumbnail" />
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Reset the token if
required.</p>
<img src="assets/screenshots/backup8.png" class="img-thumbnail" />
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Store Backup to Dropbox
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Select backup destination
as Dropbox. Enter the App key and App secret.
you'll need to register a new app in the <a href="https://www.dropbox.com/developers/apps" target="_blank">App
Console</a>.
Select Dropbox API app and choose your app's permission (files.content.write and files.content.read
permissions
required).
</p>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Install python dropbox
library (pip install dropbox).</p>
<img src="assets/screenshots/backup9.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Setup refresh token</p>
<img src="assets/screenshots/backup10.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Get the authorization code
and click confirm.</p>
<img src="assets/screenshots/backup11.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Reset the refresh token if
required</p>
<img src="assets/screenshots/backup12.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Store Backup to Onedrive
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Select backup destination
as onedrive. Enter the App key and App secret.
you'll need to register a new app in the <a href="https://portal.azure.com/" target="_blank">Microsoft Azure
portal</a>.
While registering the app for the Redirect URI restrictions, copy your Odoo database URI followed by
/onedrive/authentication. Example:</p>
<img src="assets/screenshots/onedrive1.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Copy the Client ID</p>
<img src="assets/screenshots/onedrive2.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Generate Client Secret.</p>
<img src="assets/screenshots/onedrive3.png" class="img-thumbnail">
<img src="assets/screenshots/onedrive4.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">get onedrive folder ID,
where need to store the backup files.</p>
<img src="assets/screenshots/onedrive5.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Configure the backup</p>
<img src="assets/screenshots/onedrive6.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Setup Tokens, it will be
redirected to an authorization page.</p>
<img src="assets/screenshots/onedrive7.png" class="img-thumbnail">
<img src="assets/screenshots/onedrive8.png" class="img-thumbnail">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Reset the token if required
</p>
<img src="assets/screenshots/onedrive9.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Automatically Remove Old
Backups</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">TEnable auto remove option,
specify number of days to remove backups.</p>
<img src="assets/screenshots/backup13.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Notify User on Success
and Failure of Backup Generation</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">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>
<img src="assets/screenshots/backup14.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Successful backup
notification email</h3>
<img src="assets/screenshots/backup18.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Notification email when
backup generation failed</h3>
<img src="assets/screenshots/backup17.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Scheduled Action For
Generating Backup</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">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.</p>
<img src="assets/screenshots/backup15.png" class="img-thumbnail">
<img src="assets/screenshots/backup16.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/dynamic_accounts_report/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/1.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/custom_gantt_view/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/2.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/project_custom_gantt/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/3.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/account_reports_xlsx/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/4.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/base_accounting_kit/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/5.gif">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/hr_payroll_community/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/6.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev" style="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="#demo1" data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right" style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center d-flex justify-content-center align-items-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!-- END OF END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48" style="width: 42px; height: 42px;" />
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help? Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52" style="width: 52px; height: 52px;" />
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31" style="width:144px; height: 31px; margin-top: 40px;" />
</div>
</div>
</div>
<!-- END OF SUPPORT -->

212
auto_database_backup/views/db_backup_configure_views.xml

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- Database backup configuration views-->
<record id="view_db_backup_configure_list" model="ir.ui.view">
<field name="name">db.backup.configure.list</field>
<field name="model">db.backup.configure</field>
<field name="arch" type="xml">
<tree decoration-muted="(not active)">
<field name="name"/>
<field name="db_name"/>
<field name="backup_destination"/>
<field name="active"/>
</tree>
</field>
</record>
<record id="view_db_backup_configure_form" model="ir.ui.view">
<field name="name">db.backup.configure.form</field>
<field name="model">db.backup.configure</field>
<field name="arch" type="xml">
<form>
<sheet>
<div class="oe_title">
<h1>
<field name="name" placeholder="Name..."/>
</h1>
</div>
<group>
<group>
<field name="db_name"/>
<field name="master_pwd" password="True"/>
<field name="backup_format"/>
<field name="active" widget="boolean_toggle"/>
</group>
<group>
<field name="backup_destination" required="1"/>
<field name="backup_path" attrs="{'invisible': [('backup_destination', '!=', 'local')], 'required': [('backup_destination', '=', 'local')]}"/>
<field name="ftp_host" attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}"/>
<field name="ftp_port" attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}"/>
<field name="ftp_user" attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}"/>
<field name="ftp_password" attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}" password="True"/>
<field name="ftp_path" attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}"/>
<field name="sftp_host" attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}"/>
<field name="sftp_port" attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}"/>
<field name="sftp_user" attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}"/>
<field name="sftp_password" attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}" password="True"/>
<field name="sftp_path" attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}"/>
<field name="gdrive_client_id" string="Client ID" attrs="{'invisible': [('backup_destination', '!=', 'google_drive')], 'required': [('backup_destination', '=', 'google_drive')]}"/>
<field name="gdrive_client_secret" string="Client Secret" attrs="{'invisible': [('backup_destination', '!=', 'google_drive')], 'required': [('backup_destination', '=', 'google_drive')]}" password="True"/>
<field name="gdrive_redirect_uri" string="Redirect URI" attrs="{'invisible': [('backup_destination', '!=', 'google_drive')]}"/>
<field name="gdrive_access_token" password="True" invisible="1"/>
<field name="gdrive_refresh_token" password="True" invisible="1"/>
<field name="gdrive_token_validity" invisible="1"/>
<field name="google_drive_folderid" attrs="{'invisible': [('backup_destination', '!=', 'google_drive')], 'required': [('backup_destination', '=', 'google_drive')]}"/>
<field name="dropbox_client_id" string="App Key" attrs="{'invisible': [('backup_destination', '!=', 'dropbox')], 'required': [('backup_destination', '=', 'dropbox')]}" password="True"/>
<field name="dropbox_client_secret" string="App Secret" attrs="{'invisible': [('backup_destination', '!=', 'dropbox')], 'required': [('backup_destination', '=', 'dropbox')]}" password="True"/>
<field name="onedrive_client_id" string="Client ID" attrs="{'invisible': [('backup_destination', '!=', 'onedrive')], 'required': [('backup_destination', '=', 'onedrive')]}"/>
<field name="onedrive_client_secret" string="Client Secret" attrs="{'invisible': [('backup_destination', '!=', 'onedrive')], 'required': [('backup_destination', '=', 'onedrive')]}" password="True"/>
<field name="onedrive_redirect_uri" string="Redirect URI" attrs="{'invisible': [('backup_destination', '!=', 'onedrive')]}"/>
<field name="onedrive_folder_id" string="Folder ID" attrs="{'invisible': [('backup_destination', '!=', 'onedrive')], 'required': [('backup_destination', '=', 'onedrive')]}"/>
<field name="onedrive_access_token" string="Access Token" invisible="1" password="True"/>
<field name="onedrive_refresh_token" string="Refresh Token" invisible="1" password="True"/>
<field name="onedrive_token_validity" string="Token Validity" invisible="1"/>
<field name="is_onedrive_token_generated" invisible="1"/>
<field name="is_google_drive_token_generated" invisible="1"/>
<div attrs="{'invisible': [('backup_destination', '!=', 'dropbox')]}">
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'dropbox'), ('is_dropbox_token_generated', '=', False)]}">
<i class="text-success fa fa-check"></i>
Refresh token set
</div>
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'dropbox'), ('is_dropbox_token_generated', '=', True)]}">
<i class="fa fa-exclamation-triangle text-warning"></i>
No refresh token set
</div>
</div>
<div attrs="{'invisible': [('backup_destination', '!=', 'dropbox')]}">
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'dropbox'), ('is_dropbox_token_generated', '=', True)]}">
<button class="btn btn-link"
name="action_get_dropbox_auth_code"
type="object">
<i class="fa fa-arrow-right"></i>
Setup Token
</button>
</div>
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'dropbox'), ('is_dropbox_token_generated', '=', False)]}">
<button class="btn btn-link"
name="action_get_dropbox_auth_code"
type="object">
<i class="fa fa-arrow-right"></i>
Reset Token
</button>
</div>
</div>
<div attrs="{'invisible': [('backup_destination', '!=', 'google_drive')]}">
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'google_drive'), ('is_google_drive_token_generated', '=', False)]}">
<i class="text-success fa fa-check"></i>
Refresh token set
</div>
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'google_drive'), ('is_google_drive_token_generated', '=', True)]}">
<i class="fa fa-exclamation-triangle text-warning"></i>
No refresh token set
</div>
</div>
<div attrs="{'invisible': [('backup_destination', '!=', 'google_drive')]}">
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'google_drive'), ('is_google_drive_token_generated', '=', True)]}">
<button class="btn btn-link"
name="action_get_gdrive_auth_code"
type="object">
<i class="fa fa-arrow-right"></i>
Setup Token
</button>
</div>
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'google_drive'), ('is_google_drive_token_generated', '=', False)]}">
<button class="btn btn-link"
name="action_get_gdrive_auth_code"
type="object">
<i class="fa fa-arrow-right"></i>
Reset Token
</button>
</div>
</div>
<div attrs="{'invisible': [('backup_destination', '!=', 'onedrive')]}">
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'onedrive'), ('is_onedrive_token_generated', '=', False)]}">
<i class="text-success fa fa-check"></i>
Refresh token set
</div>
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'onedrive'), ('is_onedrive_token_generated', '=', True)]}">
<i class="fa fa-exclamation-triangle text-warning"></i>
No refresh token set
</div>
</div>
<div attrs="{'invisible': [('backup_destination', '!=', 'onedrive')]}">
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'onedrive'), ('is_onedrive_token_generated', '=', True)]}">
<button class="btn btn-link"
name="action_get_onedrive_auth_code"
type="object">
<i class="fa fa-arrow-right"></i>
Setup Token
</button>
</div>
<div attrs="{'invisible': ['|', ('backup_destination', '!=', 'onedrive'), ('is_onedrive_token_generated', '=', False)]}">
<button class="btn btn-link"
name="action_get_onedrive_auth_code"
type="object">
<i class="fa fa-arrow-right"></i>
Reset Token
</button>
</div>
</div>
</group>
<group>
<field name="notify_user"/>
<field name="user_id" attrs="{'invisible': [('notify_user', '=', False)]}"/>
</group>
<group>
<field name="dropbox_refresh_token" invisible="1"/>
<field name="is_dropbox_token_generated" invisible="1"/>
<field name="dropbox_folder"
attrs="{'invisible': [('backup_destination', '!=', 'dropbox')], 'required': [('backup_destination', '=', 'dropbox')]}"/>
<field name="auto_remove"/>
<label for="days_to_remove" class="oe_inline"
attrs="{'invisible': [('auto_remove', '=', False)]}"/>
<div attrs="{'invisible': [('auto_remove', '=', False)]}">
<field name="days_to_remove" class="oe_inline"
attrs="{'required': [('auto_remove', '=', True)]}"/>
Days
</div>
<button name="test_connection" type="object" string="Test Connection" icon="fa-television"
attrs="{'invisible': [('backup_destination', 'not in', ('ftp', 'sftp'))]}"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_db_backup_configure_search" model="ir.ui.view">
<field name="name">db.backup.configure.search</field>
<field name="model">db.backup.configure</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<field name="db_name"/>
<filter string="All" name="all" domain="['|', ('active', '=', True), ('active', '!=', True)]"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group expand="0" string="Group By">
<filter string="Backup Type" name="backup_type" domain="[]" context="{'group_by': 'backup_destination'}"/>
</group>
</search>
</field>
</record>
<record id="action_db_backup_configure" model="ir.actions.act_window">
<field name="name">Database Backup</field>
<field name="res_model">db.backup.configure</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No backup configured!
</p>
</field>
<field name="context">{'search_default_all': 1}</field>
</record>
<menuitem id="menu_db_backup" name="Automatic Database Backup" parent="base.menu_custom" sequence="10"/>
<menuitem id="menu_db_backup_configuration" parent="menu_db_backup" name="Backup Configuration"
action="action_db_backup_configure"/>
</odoo>

23
auto_database_backup/wizard/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import auth_code_wizard

48
auto_database_backup/wizard/auth_code_wizard.py

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models, fields, api, _
from werkzeug import urls
GOOGLE_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth'
GOOGLE_TOKEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token'
class AuthenticationWizard(models.TransientModel):
_name = 'authentication.wizard'
_description = 'Authentication Code Wizard'
dropbox_authorization_code = fields.Char(string='Dropbox Authorization Code')
dropbox_auth_url = fields.Char(string='Dropbox Authentication URL', compute='_compute_dropbox_auth_url')
@api.depends('dropbox_authorization_code')
def _compute_dropbox_auth_url(self):
backup_config = self.env['db.backup.configure'].browse(self.env.context.get('active_id'))
dropbox_auth_url = backup_config.get_dropbox_auth_url()
for rec in self:
rec.dropbox_auth_url = dropbox_auth_url
def action_setup_dropbox_token(self):
backup_config = self.env['db.backup.configure'].browse(self.env.context.get('active_id'))
backup_config.set_dropbox_refresh_token(self.dropbox_authorization_code)

27
auto_database_backup/wizard/authentication_wizard_views.xml

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_authcode_wizard_views_form" model="ir.ui.view">
<field name="name">authentication.wizard.form</field>
<field name="model">authentication.wizard</field>
<field name="arch" type="xml">
<form>
<group invisible="not context.get('dropbox_auth')">
<span>Get an authorization code and set it in the field below.</span>
<field name="dropbox_auth_url"
class="fa fa-arrow-right"
widget="url"
text="Get Authorization Code"
nolabel="1"/>
</group>
<group>
<field name="dropbox_authorization_code" required="context.get('dropbox_auth')" invisible="not context.get('dropbox_auth')"/>
</group>
<footer>
<button string="Confirm" type="object" name="action_setup_dropbox_token" class="btn-primary" invisible="not context.get('dropbox_auth')"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>
Loading…
Cancel
Save