Coverage for models / lox_backup_config.py: 47%
74 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-28 01:16 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-28 01:16 +0000
1# -*- coding: utf-8 -*-
3from odoo import models, fields, api, _
4from odoo.exceptions import UserError, ValidationError
5import logging
7_logger = logging.getLogger(__name__)
10class LoxBackupConfig(models.Model):
11 _name = 'lox.backup.config'
12 _description = 'LOX Backup Configuration'
13 _inherit = ['mail.thread', 'mail.activity.mixin']
14 _rec_name = 'name'
16 name = fields.Char(
17 string='Name',
18 default='LOX Backup Configuration',
19 required=True,
20 tracking=True,
21 )
22 active = fields.Boolean(
23 string='Active',
24 default=True,
25 tracking=True,
26 )
27 api_url = fields.Char(
28 string='API URL',
29 required=True,
30 help='LOX API base URL (e.g., https://api.lox.io)',
31 tracking=True,
32 )
33 api_key = fields.Char(
34 string='API Key',
35 required=True,
36 help='Your LOX API key',
37 groups='base.group_system',
38 )
39 source_id = fields.Char(
40 string='Source ID',
41 readonly=True,
42 help='Registered source ID in LOX system',
43 tracking=True,
44 )
45 source_registered = fields.Boolean(
46 string='Source Registered',
47 default=False,
48 readonly=True,
49 )
50 last_connection_test = fields.Datetime(
51 string='Last Connection Test',
52 readonly=True,
53 )
54 connection_status = fields.Selection([
55 ('unknown', 'Unknown'),
56 ('connected', 'Connected'),
57 ('error', 'Error'),
58 ], string='Connection Status', default='unknown', readonly=True)
60 # Backup settings
61 backup_database = fields.Boolean(
62 string='Backup Database',
63 default=True,
64 help='Include database in backups',
65 )
66 backup_filestore = fields.Boolean(
67 string='Backup Filestore',
68 default=True,
69 help='Include filestore (attachments) in backups',
70 )
71 backup_modules = fields.Boolean(
72 string='Backup Modules Info',
73 default=True,
74 help='Include list of installed modules and their versions',
75 )
77 # Retention settings
78 retention_days = fields.Integer(
79 string='Retention Days',
80 default=30,
81 help='Number of days to retain backups in LOX storage',
82 )
84 # Tags
85 default_tags = fields.Char(
86 string='Default Tags',
87 default='odoo,automated',
88 help='Comma-separated tags to apply to all backups',
89 )
91 # Statistics
92 total_backups = fields.Integer(
93 string='Total Backups',
94 compute='_compute_backup_stats',
95 store=False,
96 )
97 last_backup_date = fields.Datetime(
98 string='Last Backup',
99 compute='_compute_backup_stats',
100 store=False,
101 )
103 # Schedules
104 schedule_ids = fields.One2many(
105 'lox.backup.schedule',
106 'config_id',
107 string='Backup Schedules',
108 )
110 # Logs
111 log_ids = fields.One2many(
112 'lox.backup.log',
113 'config_id',
114 string='Backup Logs',
115 )
117 # Profiles
118 profile_ids = fields.One2many(
119 'lox.backup.profile',
120 'config_id',
121 string='Backup Profiles',
122 )
124 _sql_constraints = [
125 ('name_unique', 'UNIQUE(name)', 'Configuration name must be unique!'),
126 ]
128 @api.depends('log_ids')
129 def _compute_backup_stats(self):
130 for record in self:
131 logs = self.env['lox.backup.log'].search([
132 ('config_id', '=', record.id),
133 ('status', '=', 'completed'),
134 ])
135 record.total_backups = len(logs)
136 if logs:
137 record.last_backup_date = max(logs.mapped('create_date'))
138 else:
139 record.last_backup_date = False
141 def action_test_connection(self):
142 """Test API connection"""
143 self.ensure_one()
144 api = self.env['lox.api'].create_client(self)
146 try:
147 result = api.test_connection()
148 if result.get('success'):
149 self.write({
150 'connection_status': 'connected',
151 'last_connection_test': fields.Datetime.now(),
152 })
153 return {
154 'type': 'ir.actions.client',
155 'tag': 'display_notification',
156 'params': {
157 'title': _('Success'),
158 'message': _('Connection to LOX API successful!'),
159 'type': 'success',
160 'sticky': False,
161 }
162 }
163 else:
164 raise UserError(_('Connection failed: %s') % result.get('error', 'Unknown error'))
165 except Exception as e:
166 self.write({
167 'connection_status': 'error',
168 'last_connection_test': fields.Datetime.now(),
169 })
170 raise UserError(_('Connection failed: %s') % str(e))
172 def action_register_source(self):
173 """Register this Odoo instance as a backup source"""
174 self.ensure_one()
175 api = self.env['lox.api'].create_client(self)
177 # Get Odoo info
178 db_name = self.env.cr.dbname
179 odoo_version = self.env['ir.module.module'].search([
180 ('name', '=', 'base')
181 ], limit=1).installed_version or 'unknown'
183 base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', '')
185 source_data = {
186 'name': f'Odoo - {db_name}',
187 'source_type': 'odoo',
188 'metadata': {
189 'database': db_name,
190 'odoo_version': odoo_version,
191 'base_url': base_url,
192 }
193 }
195 try:
196 result = api.register_source(source_data)
197 if result.get('id'):
198 self.write({
199 'source_id': result['id'],
200 'source_registered': True,
201 })
202 return {
203 'type': 'ir.actions.client',
204 'tag': 'display_notification',
205 'params': {
206 'title': _('Success'),
207 'message': _('Source registered successfully with ID: %s') % result['id'],
208 'type': 'success',
209 'sticky': False,
210 }
211 }
212 else:
213 raise UserError(_('Registration failed: %s') % result.get('error', 'Unknown error'))
214 except Exception as e:
215 raise UserError(_('Registration failed: %s') % str(e))
217 def action_run_backup(self):
218 """Run a manual backup"""
219 self.ensure_one()
221 if not self.source_registered:
222 raise UserError(_('Please register the source first.'))
224 return {
225 'name': _('Run Backup'),
226 'type': 'ir.actions.act_window',
227 'res_model': 'lox.backup.wizard',
228 'view_mode': 'form',
229 'target': 'new',
230 'context': {
231 'default_config_id': self.id,
232 }
233 }
235 def action_view_backups(self):
236 """View all backups for this configuration"""
237 self.ensure_one()
238 return {
239 'name': _('Backups'),
240 'type': 'ir.actions.act_window',
241 'res_model': 'lox.backup.log',
242 'view_mode': 'tree,form',
243 'domain': [('config_id', '=', self.id)],
244 'context': {'default_config_id': self.id},
245 }
247 def action_view_schedules(self):
248 """View all schedules for this configuration"""
249 self.ensure_one()
250 return {
251 'name': _('Schedules'),
252 'type': 'ir.actions.act_window',
253 'res_model': 'lox.backup.schedule',
254 'view_mode': 'tree,form',
255 'domain': [('config_id', '=', self.id)],
256 'context': {'default_config_id': self.id},
257 }