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

1# -*- coding: utf-8 -*- 

2 

3from odoo import models, fields, api, _ 

4from odoo.exceptions import UserError, ValidationError 

5import logging 

6 

7_logger = logging.getLogger(__name__) 

8 

9 

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' 

15 

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) 

59 

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 ) 

76 

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 ) 

83 

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 ) 

90 

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 ) 

102 

103 # Schedules 

104 schedule_ids = fields.One2many( 

105 'lox.backup.schedule', 

106 'config_id', 

107 string='Backup Schedules', 

108 ) 

109 

110 # Logs 

111 log_ids = fields.One2many( 

112 'lox.backup.log', 

113 'config_id', 

114 string='Backup Logs', 

115 ) 

116 

117 # Profiles 

118 profile_ids = fields.One2many( 

119 'lox.backup.profile', 

120 'config_id', 

121 string='Backup Profiles', 

122 ) 

123 

124 _sql_constraints = [ 

125 ('name_unique', 'UNIQUE(name)', 'Configuration name must be unique!'), 

126 ] 

127 

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 

140 

141 def action_test_connection(self): 

142 """Test API connection""" 

143 self.ensure_one() 

144 api = self.env['lox.api'].create_client(self) 

145 

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)) 

171 

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) 

176 

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' 

182 

183 base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', '') 

184 

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 } 

194 

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)) 

216 

217 def action_run_backup(self): 

218 """Run a manual backup""" 

219 self.ensure_one() 

220 

221 if not self.source_registered: 

222 raise UserError(_('Please register the source first.')) 

223 

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 } 

234 

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 } 

246 

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 }