#I9QR3B app_auto_backup增加从界面下载删除备份库的功能 V17.0

This commit is contained in:
Chill
2024-05-22 16:38:11 +08:00
parent 55e9e22f37
commit a5797b2ca3
10 changed files with 178 additions and 62 deletions

View File

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

View File

@@ -4,7 +4,7 @@
{ {
'name': "Database auto backup,数据库自动备份", 'name': "Database auto backup,数据库自动备份",
'version': '24.03.27', 'version': '24.05.22',
'summary': 'Automated backups, optimized from auto_backup of Yenthe Van Ginneken', 'summary': 'Automated backups, optimized from auto_backup of Yenthe Van Ginneken',
@@ -31,7 +31,8 @@
# any module necessary for this one to work correctly # any module necessary for this one to work correctly
'depends': [ 'depends': [
'base' 'base',
'app_odoo_customize'
], ],
'external_dependencies': { 'external_dependencies': {
'python': ['paramiko'], 'python': ['paramiko'],
@@ -43,5 +44,6 @@
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'views/backup_view.xml', 'views/backup_view.xml',
'data/backup_data.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,30 @@
# -*- 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("/download/backupfile/<path:file_path>", type="http", auth="user")
def download_backupfile(self, file_path, **kw):
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

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

View File

@@ -73,6 +73,7 @@ class DbBackup(models.Model):
email_to_notify = fields.Char('E-mail to notify', 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 ' help='Fill in the e-mail where you want to be notified that the backup failed on '
'the FTP.') 'the FTP.')
backup_details_ids = fields.One2many('db.backup.details', 'db_backup_id', 'Backup Details')
def test_sftp_connection(self, context=None): def test_sftp_connection(self, context=None):
self.ensure_one() self.ensure_one()
@@ -136,11 +137,17 @@ class DbBackup(models.Model):
fp = open(file_path, 'wb') fp = open(file_path, 'wb')
self._take_dump(rec.name, fp, 'db.backup', rec.backup_type) self._take_dump(rec.name, fp, 'db.backup', rec.backup_type)
fp.close() fp.close()
rec.backup_details_ids.create({
'name': bkp_file,
'file_path': file_path,
'url': '/download/backupfile/%s' % file_path,
'db_backup_id': rec.id,
})
except Exception as error: except Exception as error:
_logger.debug( _logger.warning(
"Couldn't backup database %s. Bad database administrator password for server running at " "Couldn't backup database %s. Bad database administrator password for server running at "
"http://%s:%s" % (rec.name, rec.host, rec.port)) "http://%s:%s" % (rec.name, rec.host, rec.port))
_logger.debug("Exact error from the exception: %s", str(error)) _logger.warning("Exact error from the exception: %s", str(error))
continue continue
# Check if user wants to write to SFTP or not. # Check if user wants to write to SFTP or not.
@@ -262,7 +269,11 @@ class DbBackup(models.Model):
# Only delete files (which are .dump and .zip), no directories. # Only delete files (which are .dump and .zip), no directories.
if os.path.isfile(fullpath) and (".dump" in f or '.zip' in f): if os.path.isfile(fullpath) and (".dump" in f or '.zip' in f):
_logger.info("Delete local out-of-date file: %s", fullpath) _logger.info("Delete local out-of-date file: %s", fullpath)
os.remove(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 # 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 # https://github.com/odoo/odoo/blob/e649200ab44718b8faefc11c2f8a9d11f2db7753/odoo/service/db.py#L209

View File

@@ -0,0 +1,37 @@
# -*- 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):
if self.file_path:
if os.path.exists(self.file_path):
os.remove(self.file_path)
return super(DbBackupDetails, self).unlink()
def action_remove_file(self):
self.ensure_one()
self.unlink()

View File

@@ -1,3 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink 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_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_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

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