[app_auto_backup] v18

This commit is contained in:
Chill
2024-11-06 15:53:11 +08:00
parent c067c819fa
commit d192e633e3
27 changed files with 1397 additions and 2 deletions

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models

View File

@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# 'author': "Yenthe Van Ginneken",
# 'website': "http://www.odoo.yenthevg.com",
# 'author': "guohuadeng@hotmail.com",
# 'website': "https://www.odooai.cn",
{
'name': "Database auto backup and Download,数据库自动备份",
'version': '24.11.06',
'summary': 'Automated and odoo database backups. easy download and manage database file. optimized from auto_backup of oca Yenthe Van Ginneken',
'description': """
1. Easy schedule database backup
2. Set remote backup and cron schedule
3. Manual backup database in one click
4. Easy download backup file or remove file for System user
11. Multi-language Support. Multi-Company Support.
12. Support Odoo 18,17,16,15,14,13,12, Enterprise and Community and odoo.sh Edition.
13. Full Open Source.
The Database Auto-Backup module enables the user to make configurations for the automatic backup of the database.
Backups can be taken on the local system or on a remote server, through SFTP.
You only have to specify the hostname, port, backup location and databasename (all will be pre-filled by default with correct data.
If you want to write to an external server with SFTP you will need to provide the IP, username and password for the remote backups.
The base of this module is taken from Odoo SA V6.1 (https://www.odoo.com/apps/modules/6.0/auto_backup/) and then upgraded and heavily expanded.
This module is made and provided by Yenthe Van Ginneken (Oocademy).
Automatic backup for all such configured databases can then be scheduled as follows:
1) Go to Settings / Technical / Automation / Scheduled actions.
2) Search the action 'Backup scheduler'.
3) Set it active and choose how often you wish to take backups.
4) If you want to write backups to a remote location you should fill in the SFTP details.
""",
'author': 'odooai.cn',
'website': "http://www.odooai.cn",
'category': 'Extra tools',
'installable': True,
'license': 'LGPL-3',
'price': 38.00,
'currency': 'EUR',
# any module necessary for this one to work correctly
'depends': [
'base',
'app_odoo_customize'
],
'external_dependencies': {
'python': ['paramiko'],
},
# always loaded
'data': [
'security/user_groups.xml',
'security/ir.model.access.csv',
'views/backup_view.xml',
'data/backup_data.xml',
'views/db_backup_details.xml',
],
}

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import main

View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
import logging
import os
from odoo import http, _
from odoo.http import request, content_disposition
from odoo.exceptions import AccessError, UserError
_logger = logging.getLogger(__name__)
class AppAutoBackup(http.Controller):
@http.route("/dbbackup/download/<path:file_path>", type="http", auth="user")
def download_backupfile(self, file_path, **kw):
_logger.warning('download_backupfile: %s', file_path)
if not self.env.user.has_group('base.group_system'):
raise UserError(_('File not found for user.'))
if os.path.exists(file_path):
try:
with open(file_path, 'rb') as file:
file_content = file.read()
file_name = file_path.split("/")[-1]
headers = [
('Content-Type', 'application/octet-stream'),
('Content-Disposition', content_disposition(file_name)),
]
return request.make_response(file_content, headers)
except Exception as e:
raise UserError(e)
else:
return 'File not found'

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<odoo>
<data noupdate="1">
<record id="backup_scheduler" model="ir.cron">
<field name="interval_type">hours</field>
<field name="name">Backup scheduler</field>
<field name="priority">5</field>
<field name="active">True</field>
<field name="interval_number">12</field>
<field name="model_id" ref="model_db_backup"/>
<field name="state">code</field>
<field name="code">model.schedule_backup()</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,449 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * app_auto_backup
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0+e-20231112\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-23 08:20+0000\n"
"PO-Revision-Date: 2024-07-23 08:20+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid ""
"<b>Warning:</b>\n"
" Use SFTP with caution! This writes files to external servers under the path you specify."
msgstr ""
"<b>警告:</b>\n"
" 使用 SFTP 要注意! 写入至外部Server的文件要在你指定的路径下。"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__folder
msgid "Absolute path for storing the backups"
msgstr "备份绝对路径"
#. module: app_auto_backup
#: model:ir.module.category,name:app_auto_backup.module_management
msgid "Auto backup access"
msgstr "备份的权限"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__send_mail_sftp_fail
msgid "Auto. E-mail on backup fail"
msgstr "FTP备份失败自动邮件通知你"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__autoremove
msgid "Auto. Remove Backups"
msgstr "自动删除备份"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Back-up view"
msgstr "备份视图"
#. module: app_auto_backup
#: model:ir.ui.menu,name:app_auto_backup.auto_backup_menu
msgid "Back-ups"
msgstr "备份"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__backup_details_ids
msgid "Backup Details"
msgstr "备份明细"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__folder
msgid "Backup Directory"
msgstr "备份目录"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__backup_type
msgid "Backup Type"
msgstr "备份类型"
#. module: app_auto_backup
#: model:ir.model,name:app_auto_backup.model_db_backup
msgid "Backup configuration record"
msgstr "备份配置记录"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Backup records"
msgstr "备份记录"
#. module: app_auto_backup
#: model:ir.actions.server,name:app_auto_backup.backup_scheduler_ir_actions_server
#: model:ir.cron,cron_name:app_auto_backup.backup_scheduler
msgid "Backup scheduler"
msgstr "数据库备份计划"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_tree
msgid "Backups"
msgstr "备份"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__days_to_keep_sftp
msgid ""
"Choose after how many days the backup should be deleted from the FTP server. For example:\n"
"If you fill in 5 the backups will be removed after 5 days from the FTP server."
msgstr ""
"选择后多少天备份应被删除从 FTP 服务器。例如: \n"
"如果你填写 5 将5 天后 从FTP 服务器 删除备份文件。"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__days_to_keep
msgid ""
"Choose after how many days the backup should be deleted. For example:\n"
"If you fill in 5 the backups will be removed after 5 days."
msgstr ""
"选择多少天后将会删除历史备份文件。如:\n"
"填入 5 则5天前的备份文件将自动删除。"
#. module: app_auto_backup
#: model:ir.actions.act_window,name:app_auto_backup.action_backup
#: model:ir.ui.menu,name:app_auto_backup.backup_conf_menu
msgid "Configure backups"
msgstr "配置备份"
#. module: app_auto_backup
#. odoo-python
#: code:addons/app_auto_backup/models/db_backup.py:0
#, python-format
msgid "Connection Test Failed!"
msgstr "连接测试失败!"
#. module: app_auto_backup
#. odoo-python
#: code:addons/app_auto_backup/models/db_backup.py:0
#, python-format
msgid ""
"Connection Test Succeeded!\n"
"Everything seems properly set up for FTP back-ups!"
msgstr ""
"连接测试成功!\n"
"所有的FTP备份设置正常"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Contact odooai.cn!"
msgstr "联系 odooai.cn"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__create_uid
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__create_uid
msgid "Created by"
msgstr "创建者"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__create_date
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__create_date
msgid "Created on"
msgstr "创建时间"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__name
msgid "Database"
msgstr "数据库"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__db_backup_id
msgid "Database Backup"
msgstr "数据库备份"
#. module: app_auto_backup
#: model:ir.model,name:app_auto_backup.model_db_backup_details
msgid "Database Backup Details"
msgstr "数据库备份明细"
#. module: app_auto_backup
#: model:ir.actions.act_window,name:app_auto_backup.action_db_backup_details
#: model:ir.ui.menu,name:app_auto_backup.menu_action_db_backup_details
msgid "Database backups"
msgstr "数据库备份管理"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__name
msgid "Database you want to schedule backups for"
msgstr "计划备份的数据库"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__display_name
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__display_name
msgid "Display Name"
msgstr "显示名称"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.db_backup_details_tree_view
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Download File"
msgstr "下载文件"
#. module: app_auto_backup
#: model:ir.model.fields.selection,name:app_auto_backup.selection__db_backup__backup_type__dump
msgid "Dump"
msgstr ""
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__email_to_notify
msgid "E-mail to notify"
msgstr "提醒E-mail地址"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__file_path
msgid "File Path"
msgstr "文件路径"
#. module: app_auto_backup
#. odoo-python
#: code:addons/app_auto_backup/models/db_backup_details.py:0
#, python-format
msgid "File Path or URL not found."
msgstr "无法找到该文件路径或URL"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__email_to_notify
msgid ""
"Fill in the e-mail where you want to be notified that the backup failed on "
"the FTP."
msgstr "FTP备份失败时邮件通知你详细信息"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "For example: /odoo/backups/"
msgstr "如:/odoo/backups/"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Go to Settings / Technical / Automation / Scheduled Actions."
msgstr "点击 设置 / 技术 / 自动化 / 计划的动作"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Help"
msgstr "帮助"
#. module: app_auto_backup
#. odoo-python
#: code:addons/app_auto_backup/models/db_backup.py:0
#, python-format
msgid "Here is what we got instead:\n"
msgstr "这里是我们 is what we got instead:\n"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__host
msgid "Host"
msgstr "服务器"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__id
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__id
msgid "ID"
msgstr ""
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__sftp_host
msgid "IP Address SFTP Server"
msgstr " SFTP 服务器 IP 地址"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__send_mail_sftp_fail
msgid ""
"If you check this option you can choose to automaticly get e-mailed when the"
" backup to the external server failed."
msgstr "如果您选中此选项,您可以选择自动收到通过邮件发送到外部服务器备份失败的信息。"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__autoremove
msgid ""
"If you check this option you can choose to automaticly remove the backup "
"after xx days"
msgstr "如果您选中此选项,您可以指定需要写入 sftp 的远程服务器的详细信息。"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__sftp_write
msgid ""
"If you check this option you can specify the details needed to write to a "
"remote server with SFTP."
msgstr "如果勾选此项,您可以进行远程 SFTP 备份。"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup____last_update
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details____last_update
msgid "Last Modified on"
msgstr "最后更新时间"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__write_uid
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__write_uid
msgid "Last Updated by"
msgstr "最后更新者"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__write_date
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__write_date
msgid "Last Updated on"
msgstr "最后更新日期"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Local backup configuration"
msgstr "本地备份配置"
#. module: app_auto_backup
#: model:res.groups,name:app_auto_backup.group_manager
msgid "Manager"
msgstr "备份管理员"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__name
msgid "Name"
msgstr "文件名"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Need more help?"
msgstr "需要更多帮助吗?"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__sftp_password
msgid "Password User SFTP Server"
msgstr " SFTP服务器密码"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__sftp_path
msgid "Path external server"
msgstr "服务器目录"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__port
msgid "Port"
msgstr "端口"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.db_backup_details_tree_view
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Remove File"
msgstr "删除文件"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__days_to_keep_sftp
msgid "Remove SFTP after x days"
msgstr "多少天后从服务器删除"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__days_to_keep
msgid "Remove after x days"
msgstr "多少天后删除"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Run Backup"
msgstr "执行备份"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "SFTP"
msgstr ""
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__sftp_port
msgid "SFTP Port"
msgstr "SFTP 端口"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Search the action named 'Backup scheduler'."
msgstr "搜索计划备份调度程序“备份计划”。"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid ""
"Set the scheduler to active and fill in how often you want backups "
"generated."
msgstr "设置计划动作为有效,并填写备份间隔时间,间隔时间单位,间隔次数,执行时间等数据库具体备份方案。"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "Test SFTP Connection"
msgstr "测试 SFTP 连接"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__sftp_host
msgid "The IP address from your remote server. For example 192.168.0.1"
msgstr "SFTP服务器的 IP 地址。例如: 192.168.0.1"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__sftp_path
msgid ""
"The location to the folder where the dumps should be written to. For example /odoo/backups/.\n"
"Files will then be written to /odoo/backups/ on your remote server."
msgstr ""
"转储应将写入的文件夹位置。例如 /odoo/backups/远程服务器上,然后将写入 /odoo/backups/.\n"
"Files。"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__sftp_password
msgid ""
"The password from the user where the SFTP connection should be made with. "
"This is the password from the user on the external server."
msgstr "从 SFTP 服务器连接该用户的密码。这是SFTP服务器上的用户密码。"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__sftp_port
msgid "The port on the FTP server that accepts SSH/SFTP calls."
msgstr "接受 SSH/SFTP 使用的FTP 服务器上的端口。"
#. module: app_auto_backup
#: model:ir.model.fields,help:app_auto_backup.field_db_backup__sftp_user
msgid ""
"The username where the SFTP connection should be made with. This is the user"
" on the external server."
msgstr "SFTP 连接使用该用户名。这是在SFTP服务器上的用户。"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid ""
"This configures the scheduler for automatic backup of the given database running on given host\n"
" at given port on regular intervals.\n"
" <br/>\n"
" Automatic backups of the database can be scheduled as follows:"
msgstr "配置适用指定数据库备份 在设置服务器端口定期运行"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup_details__url
msgid "URL"
msgstr ""
#. module: app_auto_backup
#: model:ir.module.category,description:app_auto_backup.module_management
msgid "User access level for this module"
msgstr "本模块用户权限"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__sftp_user
msgid "Username SFTP Server"
msgstr "SFTP服务器用户名"
#. module: app_auto_backup
#: model_terms:ir.ui.view,arch_db:app_auto_backup.view_backup_config_form
msgid "View Cron"
msgstr "查看定时任务"
#. module: app_auto_backup
#: model:ir.model.fields,field_description:app_auto_backup.field_db_backup__sftp_write
msgid "Write to external server with sftp"
msgstr "SFtp备份至远程服务器"
#. module: app_auto_backup
#: model:ir.model.fields.selection,name:app_auto_backup.selection__db_backup__backup_type__zip
msgid "Zip"
msgstr "Zip压缩包"

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import db_backup
from . import db_backup_details

View File

@@ -0,0 +1,360 @@
# -*- coding: utf-8 -*-
import os
import logging
import datetime
import time
import shutil
import subprocess
import json
import tempfile
import odoo
from odoo import models, fields, api, tools, _
from odoo.exceptions import ValidationError, AccessDenied
from odoo.tools.misc import exec_pg_environ, find_pg_tool
_logger = logging.getLogger(__name__)
try:
import paramiko
except ImportError:
raise ImportError(
'This module needs paramiko to automatically write backups to the FTP through SFTP. '
'Please install paramiko on your system. (sudo pip3 install paramiko)')
class DbBackup(models.Model):
_name = 'db.backup'
_description = 'Backup configuration record'
def _get_db_name(self):
dbName = self._cr.dbname
return dbName
# Columns for local server configuration
host = fields.Char('Host', required=True, default='localhost')
port = fields.Char('Port', required=True, default=8069)
name = fields.Char('Database', required=True, help='Database you want to schedule backups for',
default=_get_db_name)
folder = fields.Char('Backup Directory', help='Absolute path for storing the backups', required=True,
default='/usr/lib/python3/dist-packages/odoo/backups')
backup_type = fields.Selection([('zip', 'Zip'), ('dump', 'Dump')], 'Backup Type', required=True, default='zip')
autoremove = fields.Boolean('Auto. Remove Backups',
help='If you check this option you can choose to automaticly remove the backup '
'after xx days')
days_to_keep = fields.Integer('Remove after x days',
help="Choose after how many days the backup should be deleted. For example:\n"
"If you fill in 5 the backups will be removed after 5 days.",
required=True)
# Columns for external server (SFTP)
sftp_write = fields.Boolean('Write to external server with sftp',
help="If you check this option you can specify the details needed to write to a remote "
"server with SFTP.")
sftp_path = fields.Char('Path external server',
help='The location to the folder where the dumps should be written to. For example '
'/odoo/backups/.\nFiles will then be written to /odoo/backups/ on your remote server.')
sftp_host = fields.Char('IP Address SFTP Server',
help='The IP address from your remote server. For example 192.168.0.1')
sftp_port = fields.Integer('SFTP Port', help='The port on the FTP server that accepts SSH/SFTP calls.', default=22)
sftp_user = fields.Char('Username SFTP Server',
help='The username where the SFTP connection should be made with. This is the user on the '
'external server.')
sftp_password = fields.Char('Password User SFTP Server',
help='The password from the user where the SFTP connection should be made with. This '
'is the password from the user on the external server.')
days_to_keep_sftp = fields.Integer('Remove SFTP after x days',
help='Choose after how many days the backup should be deleted from the FTP '
'server. For example:\nIf you fill in 5 the backups will be removed after '
'5 days from the FTP server.',
default=30)
send_mail_sftp_fail = fields.Boolean('Auto. E-mail on backup fail',
help='If you check this option you can choose to automaticly get e-mailed '
'when the backup to the external server failed.')
email_to_notify = fields.Char('E-mail to notify',
help='Fill in the e-mail where you want to be notified that the backup failed on '
'the FTP.')
backup_details_ids = fields.One2many('db.backup.details', 'db_backup_id', 'Backup Details')
def test_sftp_connection(self, context=None):
self.ensure_one()
# Check if there is a success or fail and write messages
message_title = ""
message_content = ""
error = ""
has_failed = False
for rec in self:
path_to_write_to = rec.sftp_path
ip_host = rec.sftp_host
port_host = rec.sftp_port
username_login = rec.sftp_user
password_login = rec.sftp_password
# Connect with external server over SFTP, so we know sure that everything works.
try:
s = paramiko.SSHClient()
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
s.connect(ip_host, port_host, username_login, password_login, timeout=10)
sftp = s.open_sftp()
sftp.close()
message_title = _("Connection Test Succeeded!\nEverything seems properly set up for FTP back-ups!")
except Exception as e:
_logger.critical('There was a problem connecting to the remote ftp: %s', str(e))
error += str(e)
has_failed = True
message_title = _("Connection Test Failed!")
if len(rec.sftp_host) < 8:
message_content += "\nYour IP address seems to be too short.\n"
message_content += _("Here is what we got instead:\n")
finally:
if s:
s.close()
if has_failed:
raise ValidationError(message_title + '\n\n' + message_content + "%s" % str(error))
else:
raise ValidationError(message_title + '\n\n' + message_content)
@api.model
def schedule_backup(self):
conf_ids = self.search([])
for rec in conf_ids:
try:
if not os.path.isdir(rec.folder):
os.makedirs(rec.folder)
except:
raise
# Create name for dumpfile.
bkp_file = '%s_%s.%s' % (time.strftime('%Y_%m_%d_%H_%M_%S'), rec.name, rec.backup_type)
file_path = os.path.join(rec.folder, bkp_file)
uri = 'http://' + rec.host + ':' + rec.port
bkp = ''
fp = open(file_path, 'wb')
try:
# try to backup database and write it away
fp = open(file_path, 'wb')
self._take_dump(rec.name, fp, 'db.backup', rec.backup_type)
fp.close()
rec.backup_details_ids.create({
'name': bkp_file,
'file_path': file_path,
'url': '/dbbackup/download%s' % file_path,
'db_backup_id': rec.id,
})
except Exception as error:
_logger.warning(
"Couldn't backup database %s. Bad database administrator password for server running at "
"http://%s:%s" % (rec.name, rec.host, rec.port))
_logger.warning("Exact error from the exception: %s", str(error))
continue
# Check if user wants to write to SFTP or not.
if rec.sftp_write is True:
try:
# Store all values in variables
dir = rec.folder
path_to_write_to = rec.sftp_path
ip_host = rec.sftp_host
port_host = rec.sftp_port
username_login = rec.sftp_user
password_login = rec.sftp_password
_logger.debug('sftp remote path: %s' % path_to_write_to)
try:
s = paramiko.SSHClient()
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
s.connect(ip_host, port_host, username_login, password_login, timeout=20)
sftp = s.open_sftp()
except Exception as error:
_logger.critical('Error connecting to remote server! Error: %s', str(error))
try:
sftp.chdir(path_to_write_to)
except IOError:
# Create directory and subdirs if they do not exist.
current_directory = ''
for dirElement in path_to_write_to.split('/'):
current_directory += dirElement + '/'
try:
sftp.chdir(current_directory)
except:
_logger.info('(Part of the) path didn\'t exist. Creating it now at %s', current_directory)
# Make directory and then navigate into it
sftp.mkdir(current_directory, 777)
sftp.chdir(current_directory)
pass
sftp.chdir(path_to_write_to)
# Loop over all files in the directory.
for f in os.listdir(dir):
if rec.name in f:
fullpath = os.path.join(dir, f)
if os.path.isfile(fullpath):
try:
sftp.stat(os.path.join(path_to_write_to, f))
_logger.debug(
'File %s already exists on the remote FTP Server ------ skipped' % fullpath)
# This means the file does not exist (remote) yet!
except IOError:
try:
# sftp.put(fullpath, path_to_write_to)
sftp.put(fullpath, os.path.join(path_to_write_to, f))
_logger.info('Copying File % s------ success' % fullpath)
except Exception as err:
_logger.critical(
'We couldn\'t write the file to the remote server. Error: ' + str(err))
# Navigate in to the correct folder.
sftp.chdir(path_to_write_to)
# Loop over all files in the directory from the back-ups.
# We will check the creation date of every back-up.
for file in sftp.listdir(path_to_write_to):
if rec.name in file:
# Get the full path
fullpath = os.path.join(path_to_write_to, file)
# Get the timestamp from the file on the external server
timestamp = sftp.stat(fullpath).st_mtime
createtime = datetime.datetime.fromtimestamp(timestamp)
now = datetime.datetime.now()
delta = now - createtime
# If the file is older than the days_to_keep_sftp (the days to keep that the user filled in
# on the Odoo form it will be removed.
if delta.days >= rec.days_to_keep_sftp:
# Only delete files, no directories!
if ".dump" in file or '.zip' in file:
_logger.info("Delete too old file from SFTP servers: %s", file)
sftp.unlink(file)
# Close the SFTP session.
sftp.close()
except Exception as e:
_logger.debug('Exception! We couldn\'t back up to the FTP server..')
# At this point the SFTP backup failed. We will now check if the user wants
# an e-mail notification about this.
if rec.send_mail_sftp_fail:
try:
ir_mail_server = self.env['ir.mail_server'].search([], order='sequence asc', limit=1)
message = "Dear,\n\nThe backup for the server " + rec.host + " (IP: " + rec.sftp_host + \
") failed. Please check the following details:\n\nIP address SFTP server: " + \
rec.sftp_host + "\nUsername: " + rec.sftp_user + \
"\n\nError details: " + tools.ustr(e) + \
"\n\nWith kind regards"
catch_all_domain = self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain")
response_mail = "auto_backup@%s" % catch_all_domain if catch_all_domain else self.env.user.partner_id.email
msg = ir_mail_server.build_email(response_mail, [rec.email_to_notify],
"Backup from " + rec.host + "(" + rec.sftp_host +
") failed",
message)
ir_mail_server.send_email(msg)
except Exception:
pass
"""
Remove all old files (on local server) in case this is configured..
"""
if rec.autoremove:
directory = rec.folder
# Loop over all files in the directory.
for f in os.listdir(directory):
fullpath = os.path.join(directory, f)
# Only delete the ones wich are from the current database
# (Makes it possible to save different databases in the same folder)
if rec.name in fullpath:
timestamp = os.stat(fullpath).st_ctime
createtime = datetime.datetime.fromtimestamp(timestamp)
now = datetime.datetime.now()
delta = now - createtime
if delta.days >= rec.days_to_keep:
# Only delete files (which are .dump and .zip), no directories.
if os.path.isfile(fullpath) and (".dump" in f or '.zip' in f):
_logger.info("Delete local out-of-date file: %s", fullpath)
backup_details_id = self.env['db.backup.details'].search([('file_path', '=', fullpath)])
if backup_details_id:
backup_details_id.unlink()
else:
os.remove(fullpath)
# This is more or less the same as the default Odoo function at
# https://github.com/odoo/odoo/blob/e649200ab44718b8faefc11c2f8a9d11f2db7753/odoo/service/db.py#L209
# The main difference is that we do not do have a wrapper for the function check_db_management_enabled here and
# that we authenticate based on the cron its user id and by checking if we have 'db.backup' defined in the function
# call. Since this function is called from the cron and since we have these security checks on model and on user_id
# its pretty impossible to hack any way to take a backup. This allows us to disable the Odoo database manager
# which is a MUCH safer way
def _take_dump(self, db_name, stream, model, backup_format='zip'):
"""Dump database `db` into file-like object `stream` if stream is None
return a file object with the dump """
cron_user_id = self.env.ref('app_auto_backup.backup_scheduler').user_id.id
if self._name != 'db.backup' or cron_user_id != self.env.user.id:
_logger.error('Unauthorized database operation. Backups should only be available from the cron job.')
raise AccessDenied()
_logger.info('DUMP DB: %s format %s', db_name, backup_format)
cmd = [find_pg_tool('pg_dump'), '--no-owner', db_name]
env = exec_pg_environ()
if backup_format == 'zip':
with tempfile.TemporaryDirectory() as dump_dir:
filestore = odoo.tools.config.filestore(db_name)
if os.path.exists(filestore):
shutil.copytree(filestore, os.path.join(dump_dir, 'filestore'))
with open(os.path.join(dump_dir, 'manifest.json'), 'w') as fh:
db = odoo.sql_db.db_connect(db_name)
with db.cursor() as cr:
json.dump(self._dump_db_manifest(cr), fh, indent=4)
cmd.insert(-1, '--file=' + os.path.join(dump_dir, 'dump.sql'))
subprocess.run(cmd, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, check=True)
if stream:
odoo.tools.osutil.zip_dir(dump_dir, stream, include_dir=False, fnct_sort=lambda file_name: file_name != 'dump.sql')
else:
t=tempfile.TemporaryFile()
odoo.tools.osutil.zip_dir(dump_dir, t, include_dir=False, fnct_sort=lambda file_name: file_name != 'dump.sql')
t.seek(0)
return t
else:
cmd.insert(-1, '--format=c')
process = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, _ = process.communicate()
if stream:
# shutil.copyfileobj(stdout, stream)
stream.write(stdout)
else:
return stdout
def _dump_db_manifest(self, cr):
pg_version = "%d.%d" % divmod(cr._obj.connection.server_version / 100, 100)
cr.execute("SELECT name, latest_version FROM ir_module_module WHERE state = 'installed'")
modules = dict(cr.fetchall())
manifest = {
'odoo_dump': '1',
'db_name': cr.dbname,
'version': odoo.release.version,
'version_info': odoo.release.version_info,
'major_version': odoo.release.major_version,
'pg_version': pg_version,
'modules': modules,
}
return manifest
def action_view_cron(self):
self.ensure_one()
action = self.env.ref('base.ir_cron_act', False).sudo().read()[0]
cron = self.env.ref('app_auto_backup.backup_scheduler', False)
if action and cron:
action['views'] = [(self.env.ref('base.ir_cron_view_form').id, 'form')]
action['res_id'] = cron.id
return action
else:
return False
def action_run_cron(self):
self.ensure_one()
cron = self.env.ref('app_auto_backup.backup_scheduler', False)
if cron:
cron.method_direct_trigger()
return True

View File

@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
import os
from odoo import api, fields, models, _
from odoo.exceptions import AccessError, UserError
class DbBackupDetails(models.Model):
_name = 'db.backup.details'
_description = 'Database Backup Details'
name = fields.Char(string='Name')
file_path = fields.Char(string="File Path")
url = fields.Char(string='URL')
db_backup_id = fields.Many2one('db.backup', 'Database Backup')
def action_download_file(self):
self.ensure_one()
if not self.file_path or not self.url:
raise UserError(_("File Path or URL not found."))
else:
return {
'type': 'ir.actions.act_url',
'url': self.url,
'target': 'new',
}
def unlink(self):
for rec in self:
try:
if rec.file_path:
if os.path.exists(rec.file_path):
os.remove(rec.file_path)
except Exception as e:
pass
return super(DbBackupDetails, self).unlink()
def action_remove_file(self):
self.ensure_one()
self.unlink()

View File

@@ -0,0 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
admin_access, db_backup admin access,model_db_backup,base.group_no_one,1,1,1,1
admin_security_rule, Model db_backup admin access,model_db_backup,app_auto_backup.group_manager,1,1,1,1
admin_db_backup_details, Model db_backup_details admin access,model_db_backup_details,app_auto_backup.group_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 admin_access db_backup admin access model_db_backup base.group_no_one 1 1 1 1
3 admin_security_rule Model db_backup admin access model_db_backup app_auto_backup.group_manager 1 1 1 1
4 admin_db_backup_details Model db_backup_details admin access model_db_backup_details app_auto_backup.group_manager 1 1 1 1

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record model="ir.module.category" id="module_management">
<field name="name">Auto backup access</field>
<field name="description">User access level for this module</field>
<field name="sequence">3</field>
</record>
<record id="group_manager" model="res.groups">
<field name="name">Manager</field>
<field name="category_id" ref="app_auto_backup.module_management"/>
</record>
<!-- group_system 系统用户自动拥有备份管理员 -->
<record id="base.group_system" model="res.groups">
<field name="implied_ids" eval="[(4, ref('app_auto_backup.group_manager'))]"/>
</record>
</data>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -0,0 +1,267 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (C) 2009~2024 odooAi.cn
##############################################################################
-->
<html>
<!-- begin title-->
<section class="oe_container container o_cc o_cc2">
<h2 class="text-center bg-warning text-white pt24 pb24">Database auto backup. Easy schedule backup and Download </h2>
<h3 class="text-center">数据库自动备份及快速下载</h3>
</section>
<!-- end title-->
<section class="oe_container container">
<div class="oe_row oe_spaced" >
<div class="row">
<div class="oe_row">
<h3>Latest update: v18.24.11.06</h3>
<div class="row">
<img class="oe_demo oe_screenshot img img-fluid" style="max-height: 100%;" src="banner.png">
</div>
<div class="oe_span12 oe_spaced">
<div class="alert alert-info" style="padding:8px;font-weight: 300; font-size: 20px;">
<i class="fa fa-hand-o-right"></i><b> Key features: </b>
<ul class="list-unstyled">
<li>
<i class="fa fa-check-square-o text-primary"></i>
1. Easy schedule database backup
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
2. Set remote backup and cron schedule
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
3. Manual backup database in one click
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
4. Easy download backup file or remove file for System user
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
11. Multi-language Support. Multi-Company Support.
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
12. Support Odoo 18,17,16,15,14,13,12, Enterprise and Community and odoo.sh Edition.
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
13. Full Open Source.
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- quick demo-->
<section class="oe_container container">
<div class="oe_row oe_spaced">
<h2 class="bg-warning text-center pt8 pb8 mt16 mb16">1. Easy schedule database backup</h2>
<h4 class="oe_slogan">快速按日程自动备份,方便的直接下载 </h4>
<div class="oe_demo oe_screenshot img img-fluid">
<img src="demo1.jpg"/>
</div>
</div>
</section>
<section class="oe_container container">
<div class="oe_row oe_spaced">
<h2 class="bg-warning text-center pt8 pb8 mt16 mb16">2. Set remote backup and cron schedule</h2>
<h4 class="oe_slogan">支持远程备份 </h4>
<div class="oe_demo oe_screenshot img img-fluid">
<img src="demo2.jpg"/>
</div>
</div>
</section>
<section class="oe_container container">
<div class="oe_row oe_spaced">
<h2 class="bg-warning text-center pt8 pb8 mt16 mb16">3. Manual backup database in one click</h2>
<h4 class="oe_slogan">一键手动备份 </h4>
<div class="oe_demo oe_screenshot img img-fluid">
<img src="demo3.jpg"/>
</div>
</div>
</section>
<section class="oe_container container">
<div class="oe_row oe_spaced">
<h2 class="bg-warning text-center pt8 pb8 mt16 mb16">4. Easy download backup file or remove file for System user</h2>
<h4 class="oe_slogan">系统用户可以直接下载所有数据库备份文件,进行备份管理</h4>
<div class="oe_demo oe_screenshot img img-fluid">
<img src="demo4.jpg"/>
</div>
</div>
</section>
<!-- end quick demo-->
<section class="oe_container container">
<div class="oe_row oe_spaced">
<div class="row">
<h2 class="oe_slogan">Database Automated backups</h2>
<p>optimized from auto_backup of Yenthe Van Ginneken</p>
<h3 class="oe_slogan">A tool for all your back-ups, internal and external!</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot img img-fluid">
<img src="overview.png">
</div>
</div>
<div class="oe_span6">
<p class="oe_mt32">
Keep your Odoo data safe with this module. Take automated back-ups, remove them automatically
and even write them to an external server through an encrypted tunnel.
You can even specify how long local backups and external backups should be kept, automatically!
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=mail" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
</div>
</div>
</div>
</section>
<!-- Second block -->
<section class="container oe_dark">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan">Connect with an FTP Server</h2>
<h3 class="oe_slogan">Keep your data safe, through an SSH tunnel!</h3>
<div class="oe_span6">
<p class="oe_mt32">
Want to go even further and write your backups to an external server?
You can with this module! Specify the credentials to the server, specify a path and everything will be backed up automatically. This is done through an SSH (encrypted) tunnel, thanks to pysftp, so your data is safe!
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot img img-fluid" src="terminalssh.png">
</div>
</div>
</div>
</section>
<!--Third block -->
<section class="oe_container container">
<div class="oe_row oe_spaced">
<div class="row">
<h2 class="oe_slogan">Test connection</h2>
<h3 class="oe_slogan">Checks your credentials in one click</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot img img-fluid">
<img src="testconnection.png">
<img src="testconnectionfailed.png">
</div>
</div>
<div class="oe_span6">
<p class="oe_mt32">
Want to make sure if the connection details are correct and if Odoo can automatically write them to the remote server? Simply click on the 'Test SFTP Connection' button and you will get message telling you if everything is OK, or what is wrong!
</p>
</div>
</div>
</section>
<!-- Fourth block -->
<section class="container oe_dark">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan">E-mail on backup failure</h2>
<h3 class="oe_slogan">Stay informed of problems, automatically!</h3>
<div class="oe_span6">
<p class="oe_mt32">
Do you want to know if the database backup failed? Check the checkbox 'Auto. E-mail on backup fail' and fill in your e-mail.
Every time a backup fails you will get an e-mail in your mailbox with technical details.
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot img img-fluid" src="emailnotification.png">
</div>
</div>
</div>
</section>
<!--Fifth block -->
<section class="oe_container container">
<div class="oe_row oe_spaced">
<div class="row">
<h2 class="oe_slogan">Contact / Support</h2>
<h3 class="oe_slogan">Need help or want extra features?</h3>
</div>
<div class="oe_span6">
<p class="oe_mt32">
Need help with the configuration or want this module to have more functionalities?
Please create a bug report <a href="https://github.com/Yenthe666/auto_backup/issues">on the Github issue tracker</a>
</p>
</div>
</div>
</section>
<!-- begin free-->
<!-- end free-->
<!-- begin howto-->
<section class="oe_container container s_text_block o_colored_level pt16 pb16">
<h2 class="text-center bg-info text-white pt16 pb16">- How to setup and use -</h2>
<h3>This app need no extra module. The price already included</h3>
</section>
<section class="oe_container container">
<div class="oe_row oe_spaced">
<h4 class="pt16">
1. Buy and Install
</h4>
<h4 class="pt16">
2. Read the app description for user guide
</h4>
<h4 class="pt16">
3. Enjoy and easy use
</h4>
<div class="row">
<div class="oe_demo oe_screenshot img img-fluid">
<img src="banner.png">
</div>
</div>
<h4 class="pt16">4. More information in our FAQ</h4>
<div class="row">
https://www.odooai.cn/faq
</div>
</div>
</section>
<!-- end howto-->
<!-- begin upsell-->
<!-- end upsell-->
<!-- begin support-->
<section class="container oe_dark">
<div class="oe_row oe_spaced text-center">
<div class="row">
<h2 class="oe_slogan">Technical Help & Support</h2>
</div>
<div class="col-md-12 pad0">
<div class="oe_mt16">
<p><h4 class="pt16">
For any type of technical help & support requests, Feel free to contact us</h4></p>
<a style="background: #002e5a none repeat scroll 0% 0%; color: rgb(255, 255, 255);position: relative; overflow: hidden;"
class="btn btn-warning btn-lg" rel="nofollow" href="mailto:odoo@china.com"><span
style="height: 354px; width: 354px; top: -147.433px; left: -6.93335px;" class="o_ripple"></span>
<i class="fa fa-envelope"></i> odoo@china.com</a>
<p><h4 class="pt16">
Via QQ: 300883 (App user would not get QQ or any other IM support. Only for odoo project customize.)</h4></p>
<a style="background: #002e5a none repeat scroll 0% 0%; color: rgb(255, 255, 255);position: relative; overflow: hidden;"
class="btn btn-warning btn-lg" rel="nofollow" href="mailto:300883@qq.com"><span
style="height: 354px; width: 354px; top: -147.433px; left: -6.93335px;" class="o_ripple"></span>
<i class="fa fa-envelope"></i> 300883@qq.com</a>
</div>
<div class="oe_mt16">
<h4 class="pt16">Visit our website for more support.</h4>
<h4 class="pt16">https://www.odooai.cn</h4>
</div>
</div>
</div>
</section>
<!-- end support-->
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -0,0 +1,112 @@
<odoo>
<data>
<record id="view_backup_config_form" model="ir.ui.view">
<field name="name">db.backup.form</field>
<field name="model">db.backup</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Back-up view">
<sheet>
<div class="oe_button_box" name="button_box">
<button name="action_view_cron" string="View Cron" type="object" class="oe_stat_button" icon="fa-clock-o"/>
<button name="action_run_cron" string="Run Backup" type="object" class="oe_stat_button" icon="fa-play-circle"/>
</div>
<group col="4" colspan="4">
<separator col="2" string="Local backup configuration"/>
</group>
<group name="configuration">
<field name="host" colspan="2"/>
<field name="name"/>
<field name="port"/>
<field name="backup_type"/>
<field name="folder"/>
<field name="autoremove"/>
<field name="days_to_keep" invisible="not autoremove"/>
</group>
<group name="allow_stfp" col="4" colspan="4">
<separator col="2" string="SFTP"/>
</group>
<div style="width:50%;border-radius:10px;margin: 10px 0px;padding:15px 10px 15px 10px;
background-repeat: no-repeat;background-position: 10px center;color: #9F6000;background-color: #FEEFB3;" invisible="not sftp_write">
<b>Warning:</b>
Use SFTP with caution! This writes files to external servers under the path you specify.
</div>
<group name="sftp_configuration">
<field name="sftp_write"/>
<field name="sftp_host" invisible="not sftp_write" required="sftp_write"/>
<field name="sftp_port" invisible="not sftp_write" required="sftp_write"/>
<field name="sftp_user" invisible="not sftp_write" required="sftp_write"/>
<field name="sftp_password" invisible="not sftp_write" required="sftp_write" password="True"/>
<field name="sftp_path" invisible="not sftp_write" required="sftp_write" placeholder="For example: /odoo/backups/"/>
<field name="days_to_keep_sftp" invisible="not sftp_write" required="sftp_write"/>
<field name="send_mail_sftp_fail" invisible="not sftp_write"/>
<field name="email_to_notify" invisible="not send_mail_sftp_fail or not sftp_write" required="send_mail_sftp_fail"/>
<button name="test_sftp_connection" type="object" invisible="not sftp_write" string="Test SFTP Connection"/>
</group>
<separator string="Help" colspan="2"/>
<div name="configuration_details">
This configures the scheduler for automatic backup of the given database running on given host
at given port on regular intervals.
<br/>
Automatic backups of the database can be scheduled as follows:
<ol>
<li>
Go to Settings / Technical / Automation / Scheduled Actions.
</li>
<li>
Search the action named 'Backup scheduler'.
</li>
<li>
Set the scheduler to active and fill in how often you want backups generated.
</li>
</ol>
<p style="font-size:18px;">
Need more help?
<a href="https://www.odooai.cn">Contact odooai.cn!</a>
</p>
</div>
<notebook>
<page name="backup_details" string="Backup records">
<field name="backup_details_ids" readonly="1">
<list>
<field name="name" optional="hide"/>
<field name="file_path"/>
<field name="url" optional="hide"/>
<button name="action_download_file" type="object" title="Download File" class="fa fa-download"/>
<button name="action_remove_file" type="object" title="Remove File" class="fa fa-trash"/>
</list>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_backup_config_tree" model="ir.ui.view">
<field name="name">db.backup.tree</field>
<field name="model">db.backup</field>
<field name="type">list</field>
<field name="arch" type="xml">
<list string="Backups">
<field name='host'/>
<field name='port'/>
<field name='name'/>
<field name='folder'/>
<field name="autoremove"/>
<field name="sftp_host"/>
</list>
</field>
</record>
<record id="action_backup" model="ir.actions.act_window">
<field name="name">Configure backups</field>
<field name="res_model">db.backup</field>
<field name="view_mode">list,form</field>
<field name="view_id" ref="view_backup_config_tree"/>
</record>
<menuitem id="auto_backup_menu" name="Back-ups" sequence="9" parent="app_odoo_customize.menu_app_group"/>
<menuitem parent="auto_backup_menu" action="action_backup" id="backup_conf_menu" sequence="1"/>
</data>
</odoo>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="db_backup_details_tree_view" model="ir.ui.view">
<field name="name">db.backup.details.tree</field>
<field name="model">db.backup.details</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="file_path"/>
<field name="url" invisible="1"/>
<button name="action_download_file" type="object" title="Download File" class="fa fa-download"/>
<button name="action_remove_file" type="object" title="Remove File" class="fa fa-trash"/>
</list>
</field>
</record>
<record id="action_db_backup_details" model="ir.actions.act_window">
<field name="name">Database backups</field>
<field name="res_model">db.backup.details</field>
<field name="view_mode">list</field>
</record>
<menuitem id="menu_action_db_backup_details" action="action_db_backup_details" parent="auto_backup_menu" sequence="3"/>
</odoo>

View File

@@ -72,8 +72,8 @@
<record id="action_ir_module_addons_path" model="ir.actions.act_window">
<field name="name">Addons Paths</field>
<field name="res_model">ir.module.addons.path</field>
<field name="view_mode">kanban,tree,form</field>
<field name="view_mode">kanban,list,form</field>
<field name="context">{}</field>
<field name="domain">[]</field>
</record>
</odoo>
</odoo>