Merge lp:~unifield-team/unifield-wm/sync-odoo-task-9535 into lp:unifield-wm/sync

Proposed by jftempo
Status: Merged
Merged at revision: 505
Proposed branch: lp:~unifield-team/unifield-wm/sync-odoo-task-9535
Merge into: lp:unifield-wm/sync
Diff against target: 503 lines (+355/-7)
11 files modified
sync_client/__init__.py (+1/-0)
sync_client/__openerp__.py (+2/-0)
sync_client/backup.py (+144/-0)
sync_client/backup_view.xml (+113/-0)
sync_client/data/backupconfig.xml (+13/-0)
sync_client/data/cron.xml (+14/-0)
sync_client/security/ir.model.access.csv (+1/-0)
sync_client/sync_client.py (+55/-1)
sync_client/sync_client_view.xml (+4/-2)
sync_client/wizard/sync_manager.py (+6/-1)
sync_client/wizard/sync_wiz_view.xml (+2/-3)
To merge this branch: bzr merge lp:~unifield-team/unifield-wm/sync-odoo-task-9535
Reviewer Review Type Date Requested Status
UniField Sync Reviewer Pending
Review via email: mp+237050@code.launchpad.net
To post a comment you must log in.
478. By Nicolas Seinlet (OpenERP)

no update on backup config

479. By Nicolas Seinlet (OpenERP)

[FIX] manual launch of a background job is a manual operation

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'sync_client/__init__.py'
2--- sync_client/__init__.py 2013-10-18 08:25:44 +0000
3+++ sync_client/__init__.py 2014-10-14 12:49:38 +0000
4@@ -1,4 +1,5 @@
5 from sync_client import MAX_EXECUTED_UPDATES, MAX_EXECUTED_MESSAGES, SkipStep, BackgroundProcess, sync_process
6+import backup
7 import wizard
8 import ir_model_data
9 import monitor
10
11=== modified file 'sync_client/__openerp__.py'
12--- sync_client/__openerp__.py 2014-08-28 15:12:55 +0000
13+++ sync_client/__openerp__.py 2014-10-14 12:49:38 +0000
14@@ -33,6 +33,7 @@
15 'init_xml': [],
16 'data': [
17 'sync_client_view.xml',
18+ 'backup_view.xml',
19 'update_view.xml',
20 'message_view.xml',
21 'log_sale_purchase_view.xml',
22@@ -41,6 +42,7 @@
23 'wizard/view_entity_id.xml',
24 'monitor_view.xml',
25 'data/cron.xml',
26+ 'data/backupconfig.xml',
27 'security/ir.model.access.csv'
28 ],
29 'demo_xml': [
30
31=== added file 'sync_client/backup.py'
32--- sync_client/backup.py 1970-01-01 00:00:00 +0000
33+++ sync_client/backup.py 2014-10-14 12:49:38 +0000
34@@ -0,0 +1,144 @@
35+# -*- coding: utf-8 -*-
36+##############################################################################
37+#
38+# OpenERP, Open Source Management Solution
39+# Copyright (C) 2004-2010 OpenERP s.a. (<http://odoo.com>).
40+#
41+# This program is free software: you can redistribute it and/or modify
42+# it under the terms of the GNU Affero General Public License as
43+# published by the Free Software Foundation, either version 3 of the
44+# License, or (at your option) any later version.
45+#
46+# This program is distributed in the hope that it will be useful,
47+# but WITHOUT ANY WARRANTY; without even the implied warranty of
48+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49+# GNU Affero General Public License for more details.
50+#
51+# You should have received a copy of the GNU Affero General Public License
52+# along with this program. If not, see <http://www.gnu.org/licenses/>.
53+#
54+##############################################################################
55+
56+import os
57+from osv import osv
58+from osv import fields
59+import tools
60+from datetime import datetime
61+from tools.translate import _
62+
63+class BackupConfig(osv.osv):
64+ """ Backup configurations """
65+ _name = "backup.config"
66+ _description = "Backup configuration"
67+ _pg_psw_env_var_is_set = False
68+
69+ _columns = {
70+ 'name' : fields.char('Path to backup to', size=254),
71+ 'beforemanualsync':fields.boolean('Backup before manual sync'),
72+ 'beforeautomaticsync':fields.boolean('Backup before automatic sync'),
73+ 'aftermanualsync':fields.boolean('Backup after manual sync'),
74+ 'afterautomaticsync':fields.boolean('Backup after automatic sync'),
75+ 'scheduledbackup':fields.boolean('Scheduled backup'),
76+ }
77+
78+ _defaults = {
79+ 'name' : 'c:\\backup\\',
80+ 'beforemanualsync' : True,
81+ 'beforeautomaticsync' : True,
82+ 'aftermanualsync' : True,
83+ 'afterautomaticsync' : True,
84+ }
85+
86+ def _set_pg_psw_env_var(self):
87+ if os.name == 'nt' and not os.environ.get('PGPASSWORD', ''):
88+ os.environ['PGPASSWORD'] = tools.config['db_password']
89+ self._pg_psw_env_var_is_set = True
90+
91+ def _unset_pg_psw_env_var(self):
92+ if os.name == 'nt' and self._pg_psw_env_var_is_set:
93+ os.environ['PGPASSWORD'] = ''
94+
95+ def exp_dump_for_state(self, cr, uid, state, context=None):
96+ context = context or {}
97+ logger = context.get('logger')
98+ bkp_ids = self.search(cr, uid, [(state, '=', True)], context=context)
99+ if bkp_ids:
100+ if logger:
101+ logger.append("Database %s backup started.." % state)
102+ logger.write()
103+ self.exp_dump(cr, uid, bkp_ids, context)
104+ if logger:
105+ logger.append("Database %s backup successful" % state)
106+ logger.write()
107+
108+ def exp_dump(self, cr, uid, ids, context=None):
109+ bkp = self.browse(cr, uid, ids, context)
110+ if bkp and bkp[0]:
111+ bck = bkp[0]
112+ self._set_pg_psw_env_var()
113+
114+ cmd = ['pg_dump', '--format=c', '--no-owner']
115+ if tools.config['db_user']:
116+ cmd.append('--username=' + tools.config['db_user'])
117+ if tools.config['db_host']:
118+ cmd.append('--host=' + tools.config['db_host'])
119+ if tools.config['db_port']:
120+ cmd.append('--port=' + str(tools.config['db_port']))
121+ cmd.append(cr.dbname)
122+
123+ stdin, stdout = tools.exec_pg_command_pipe(*tuple(cmd))
124+ stdin.close()
125+ data = stdout.read()
126+ res = stdout.close()
127+ if res:
128+ raise Exception, "Couldn't dump database"
129+ self._unset_pg_psw_env_var()
130+ outfile = os.path.join(bck.name, "%s-%s.dump" % (cr.dbname, datetime.now().strftime("%Y%m%d-%H%M%S")))
131+ bkpfile = open(outfile,"wb")
132+ bkpfile.write(data)
133+ bkpfile.close()
134+ return "Backup done"
135+ raise Exception, "No backup defined"
136+
137+ def scheduled_backups(self, cr, uid, context=None):
138+ bkp_ids = self.search(cr, uid, [('scheduledbackup', '=', True)], context=context)
139+ if bkp_ids:
140+ self.exp_dump(cr, uid, bkp_ids, context=context)
141+
142+ def write(self, cr, uid, ids, vals, context=None):
143+ toret = super(BackupConfig, self).write(cr, uid, ids, vals, context=context)
144+ backups = self.browse(cr, uid, ids, context=context)
145+ #if context:
146+ # for backup in backups:
147+ # if not os.path.isdir(backup.name):
148+ # raise osv.warning(_('Error'), _("The selected path doesn't exist!"))
149+ if backups and backups[0]:
150+ #Find the scheduled action
151+ ircron_model = self.pool.get('ir.cron')
152+ cron_ids = ircron_model.search(cr, uid, ([('name', '=', 'Automatic backup'), ('model', '=', 'backup.config'), '|', ('active', '=', True), ('active', '=', False)]), context=context)
153+ crons = ircron_model.browse(cr, uid, cron_ids, context=context)
154+ for cron in crons:
155+ if cron.active != backups[0].scheduledbackup:
156+ ircron_model.write(cr, uid, [cron.id,], {'active': backups[0].scheduledbackup}, context=context)
157+ return toret
158+
159+BackupConfig()
160+
161+class ir_cron(osv.osv):
162+ _name = 'ir.cron'
163+ _inherit = 'ir.cron'
164+
165+ def write(self, cr, uid, ids, vals, context=None):
166+ toret = super(ir_cron, self).write(cr, uid, ids, vals, context=context)
167+ crons = self.browse(cr, uid, ids, context=context)
168+ if crons and crons[0] and crons[0].model=='backup.config':
169+ #Find the scheduled action
170+ bkp_model = self.pool.get('backup.config')
171+ bkp_ids = bkp_model.search(cr, uid, (['|', ('scheduledbackup', '=', True), ('scheduledbackup', '=', False)]), context=context)
172+ bkps = bkp_model.browse(cr, uid, bkp_ids, context=context)
173+ for bkp in bkps:
174+ if crons[0].active != bkp.scheduledbackup:
175+ bkp_model.write(cr, uid, [bkp.id,], {'scheduledbackup': crons[0].active}, context=context)
176+ return toret
177+
178+ir_cron()
179
180=== added file 'sync_client/backup_view.xml'
181--- sync_client/backup_view.xml 1970-01-01 00:00:00 +0000
182+++ sync_client/backup_view.xml 2014-10-14 12:49:38 +0000
183@@ -0,0 +1,113 @@
184+<?xml version="1.0" encoding="UTF-8"?>
185+<openerp>
186+ <data>
187+ <record model="ir.ui.view" id="syncback_config_tree_view">
188+ <field name="name">sync.backup.config.tree</field>
189+ <field name="model">backup.config</field>
190+ <field name="type">tree</field>
191+ <field name="arch" type="xml">
192+ <tree string="Backup Tree" hide_new_button="1" hide_delete_button="1" >
193+ <field name="name"/>
194+ <field name="beforemanualsync"/>
195+ <field name="beforeautomaticsync"/>
196+ <field name="aftermanualsync"/>
197+ <field name="afterautomaticsync"/>
198+ <field name="scheduledbackup"/>
199+ </tree>
200+ </field>
201+ </record>
202+
203+ <record model="ir.ui.view" id="syncback_config_form_view">
204+ <field name="name">sync.backup.config.form</field>
205+ <field name="model">backup.config</field>
206+ <field name="type">form</field>
207+ <field name="arch" type="xml">
208+ <form string="Backup configuration" hide_new_button="1" hide_delete_button="1" hide_duplicate_button="1">
209+ <group col="6" colspan="6">
210+ <field name="name"/>
211+ </group>
212+ <group col="4">
213+ <field name="beforemanualsync"/>
214+ <field name="beforeautomaticsync"/>
215+ <field name="aftermanualsync"/>
216+ <field name="afterautomaticsync"/>
217+ <field name="scheduledbackup"/>
218+ </group>
219+ <button type="object" string="Backup" name="exp_dump" />
220+ </form>
221+ </field>
222+ </record>
223+
224+ <record id="ir_actions_server_openbackupconfig" model="ir.actions.server">
225+ <field name="code">
226+res = obj.pool.get('ir.model.data').get_object_reference(cr, uid, 'sync_client', 'backup_config_default')
227+action = {
228+'res_model' : 'backup.config',
229+'view_type' : 'form',
230+'view_mode' : 'form,tree',
231+'type': 'ir.actions.act_window',
232+'res_id' : res[1],
233+}</field>
234+ <field eval="5" name="sequence"/>
235+ <field name="state">code</field>
236+ <field name="type">ir.actions.server</field>
237+ <field name="model_id" ref="model_backup_config"/>
238+ <field name="condition">True</field>
239+ <field name="name">Open Backup config</field>
240+ </record>
241+
242+
243+ <record id="ir_ui_menu_backupconfig" model="ir.ui.menu">
244+ <field name="name">Backup config</field>
245+ <field name="parent_id" ref="syncback_menu"/>
246+ <field name="sequence">25</field>
247+ </record>
248+
249+ <record id="ir_values_menuitem_backupconfig" model="ir.values">
250+ <field name="name">Menuitem backup config</field>
251+ <field name="key2">tree_but_open</field>
252+ <field eval="1" name="object"/>
253+ <field name="value" eval="'ir.actions.server,%s' % ref('sync_client.ir_actions_server_openbackupconfig')" />
254+ <field name="key">action</field>
255+ <field name="model">ir.ui.menu</field>
256+ <field eval="ref('ir_ui_menu_backupconfig')" name="res_id"/>
257+ </record>
258+
259+
260+
261+ <record id="ir_actions_server_opensyncbackup" model="ir.actions.server">
262+ <field name="code">
263+res = obj.pool.get('ir.model.data').get_object_reference(cr, uid, 'sync_client', 'ir_cron_automaticsyncbackup')
264+action = {
265+'res_model' : 'ir.cron',
266+'view_type' : 'form',
267+'view_mode' : 'form',
268+'type': 'ir.actions.act_window',
269+'res_id' : res[1],
270+}</field>
271+ <field eval="5" name="sequence"/>
272+ <field name="state">code</field>
273+ <field name="type">ir.actions.server</field>
274+ <field name="model_id" ref="base.model_ir_cron"/>
275+ <field name="condition">True</field>
276+ <field name="name">Open Backup cron</field>
277+ </record>
278+
279+
280+ <record id="ir_ui_menu_cron_synchrobackup" model="ir.ui.menu">
281+ <field name="name">Automatic</field>
282+ <field name="parent_id" ref="syncback_menu"/>
283+ <field name="sequence">30</field>
284+ </record>
285+
286+ <record id="ir_values_menuitem_cronbackup" model="ir.values">
287+ <field name="name">Menuitem IR CRON</field>
288+ <field name="key2">tree_but_open</field>
289+ <field eval="1" name="object"/>
290+ <field name="value" eval="'ir.actions.server,%s' % ref('ir_actions_server_opensyncbackup')" />
291+ <field name="key">action</field>
292+ <field name="model">ir.ui.menu</field>
293+ <field eval="ref('ir_ui_menu_cron_synchrobackup')" name="res_id"/>
294+ </record>
295+ </data>
296+</openerp>
297
298=== added file 'sync_client/data/backupconfig.xml'
299--- sync_client/data/backupconfig.xml 1970-01-01 00:00:00 +0000
300+++ sync_client/data/backupconfig.xml 2014-10-14 12:49:38 +0000
301@@ -0,0 +1,13 @@
302+<?xml version="1.0" encoding="UTF-8"?>
303+<openerp>
304+ <data noupdate="1">
305+ <record id="backup_config_default" model="backup.config">
306+ <field name="name">c:\backup\</field>
307+ <field eval="True" name="beforemanualsync"/>
308+ <field eval="True" name="beforeautomaticsync"/>
309+ <field eval="True" name="aftermanualsync"/>
310+ <field eval="True" name="afterautomaticsync"/>
311+ <field eval="True" name="scheduledbackup"/>
312+ </record>
313+ </data>
314+</openerp>
315
316=== modified file 'sync_client/data/cron.xml'
317--- sync_client/data/cron.xml 2013-05-16 14:00:59 +0000
318+++ sync_client/data/cron.xml 2014-10-14 12:49:38 +0000
319@@ -15,5 +15,19 @@
320 <field name="model">sync.client.entity</field>
321 </record>
322
323+ <record id="ir_cron_automaticsyncbackup" model="ir.cron">
324+ <field name="function">scheduled_backups</field>
325+ <field name="user_id">1</field>
326+ <field name="name">Automatic backup</field>
327+ <field name="interval_type">days</field>
328+ <field eval="-1" name="numbercall"/>
329+ <field eval="5" name="priority"/>
330+ <field eval="0" name="doall"/>
331+ <field eval="0" name="active"/>
332+ <field eval="1" name="interval_number"/>
333+ <field name="model">backup.config</field>
334+ <field name="active">1</field>
335+ </record>
336+
337 </data>
338 </openerp>
339
340=== modified file 'sync_client/security/ir.model.access.csv'
341--- sync_client/security/ir.model.access.csv 2013-10-18 08:25:44 +0000
342+++ sync_client/security/ir.model.access.csv 2014-10-14 12:49:38 +0000
343@@ -10,3 +10,4 @@
344 "sync_read_sync_server_connection_id","sync_read_sync_server_connection","sync.client.sync_server_connection","True","","","","sync_common.sync_read_group"
345 "sync_read_monitor_id","sync_read_monitor","sync.monitor","True","","","","sync_common.sync_read_group"
346 "sync_read_log_sale_purchase_id","sync_read_log_sale_purchase","sync.client.log_sale_purchase","True","","","","sync_common.sync_read_group"
347+"sync_backup","sync_backup","backup.config","True","True","True","True",""
348
349=== modified file 'sync_client/sync_client.py'
350--- sync_client/sync_client.py 2014-09-29 15:42:01 +0000
351+++ sync_client/sync_client.py 2014-10-14 12:49:38 +0000
352@@ -787,7 +787,13 @@
353 """
354 def sync_threaded(self, cr, uid, recover=False, context=None):
355 BackgroundProcess(cr, uid,
356- ('sync_recover' if recover else 'sync'),
357+ ('sync_recover_withbackup' if recover else 'sync_withbackup'),
358+ context).start()
359+ return True
360+
361+ def sync_manual_threaded(self, cr, uid, recover=False, context=None):
362+ BackgroundProcess(cr, uid,
363+ ('sync_manual_recover_withbackup' if recover else 'sync_manual_withbackup'),
364 context).start()
365 return True
366
367@@ -804,6 +810,30 @@
368 return True
369
370 @sync_process()
371+ def sync_recover_withbackup(self, cr, uid, context=None):
372+ """
373+ Call both pull_all_data and recover_message functions - used in manual sync wizard
374+ """
375+ #Check for a backup before automatic sync
376+ self.pool.get('backup.config').exp_dump_for_state(cr, uid, 'beforeautomaticsync', context=context)
377+ self.sync_recover(cr, uid, context=context)
378+ #Check for a backup after automatic sync
379+ self.pool.get('backup.config').exp_dump_for_state(cr, uid, 'afterautomaticsync', context=context)
380+ return {'type': 'ir.actions.act_window_close'}
381+
382+ @sync_process()
383+ def sync_manual_recover_withbackup(self, cr, uid, context=None):
384+ """
385+ Call both pull_all_data and recover_message functions - used in manual sync wizard
386+ """
387+ #Check for a backup before automatic sync
388+ self.pool.get('backup.config').exp_dump_for_state(cr, uid, 'beforemanualsync', context=context)
389+ self.sync_recover(cr, uid, context=context)
390+ #Check for a backup after automatic sync
391+ self.pool.get('backup.config').exp_dump_for_state(cr, uid, 'aftermanualsync', context=context)
392+ return {'type': 'ir.actions.act_window_close'}
393+
394+ @sync_process()
395 def sync(self, cr, uid, context=None):
396 self._logger.info("Start synchronization")
397 self.pull_update(cr, uid, context=context)
398@@ -813,6 +843,30 @@
399 self._logger.info("Synchronization succesfully done")
400 return True
401
402+ @sync_process()
403+ def sync_withbackup(self, cr, uid, context=None):
404+ """
405+ Call both pull_all_data and recover_message functions - used in manual sync wizard
406+ """
407+ #Check for a backup before automatic sync
408+ self.pool.get('backup.config').exp_dump_for_state(cr, uid, 'beforeautomaticsync', context=context)
409+ self.sync(cr, uid, context=context)
410+ #Check for a backup after automatic sync
411+ self.pool.get('backup.config').exp_dump_for_state(cr, uid, 'afterautomaticsync', context=context)
412+ return {'type': 'ir.actions.act_window_close'}
413+
414+ @sync_process()
415+ def sync_manual_withbackup(self, cr, uid, context=None):
416+ """
417+ Call both pull_all_data and recover_message functions - used in manual sync wizard
418+ """
419+ #Check for a backup before automatic sync
420+ self.pool.get('backup.config').exp_dump_for_state(cr, uid, 'beforemanualsync', context=context)
421+ self.sync(cr, uid, context=context)
422+ #Check for a backup after automatic sync
423+ self.pool.get('backup.config').exp_dump_for_state(cr, uid, 'aftermanualsync', context=context)
424+ return {'type': 'ir.actions.act_window_close'}
425+
426 def get_upgrade_status(self, cr, uid, context=None):
427 return ""
428
429
430=== modified file 'sync_client/sync_client_view.xml'
431--- sync_client/sync_client_view.xml 2013-05-28 09:34:10 +0000
432+++ sync_client/sync_client_view.xml 2014-10-14 12:49:38 +0000
433@@ -53,8 +53,8 @@
434 <field name="context">{}</field>
435 </record>
436
437- <menuitem id="main_menu"
438- name="Synchronization"
439+ <menuitem id="main_menu"
440+ name="Synchronization"
441 parent=""
442 web_icon="images/sync.jpg"
443 web_icon_hover="images/sync-hover.jpg"
444@@ -66,6 +66,8 @@
445
446 <menuitem id="mon_menu" name="Monitoring" parent="main_menu" sequence="30"/>
447
448+ <menuitem id="syncback_menu" name="Backup" parent="main_menu" sequence="25"/>
449+
450 <menuitem id="connection_manager_menu" name="Connection Manager" parent="reg_menu"
451 action="connection_manager_action"/>
452
453
454=== modified file 'sync_client/wizard/sync_manager.py'
455--- sync_client/wizard/sync_manager.py 2013-02-22 15:25:34 +0000
456+++ sync_client/wizard/sync_manager.py 2014-10-14 12:49:38 +0000
457@@ -20,6 +20,7 @@
458 ##############################################################################
459
460 from osv import osv, fields
461+from sync_client import sync_client
462
463 class sync_manager(osv.osv_memory):
464 _name = 'sync.client.sync_manager'
465@@ -43,13 +44,17 @@
466 }
467
468 def sync(self, cr, uid, ids, context=None):
469- self.pool.get('sync.client.entity').sync(cr, uid, context=context)
470+ self.pool.get('sync.client.entity').sync_manual_withbackup(cr, uid, context=context)
471 return {'type': 'ir.actions.act_window_close'}
472
473 def sync_threaded(self, cr, uid, ids, context=None):
474 self.pool.get('sync.client.entity').sync_threaded(cr, uid, context=context)
475 return {'type': 'ir.actions.act_window_close'}
476
477+ def sync_manual_threaded(self, cr, uid, ids, context=None):
478+ self.pool.get('sync.client.entity').sync_manual_threaded(cr, uid, context=context)
479+ return {'type': 'ir.actions.act_window_close'}
480+
481 def pull_data(self, cr, uid, ids, context=None):
482 self.pool.get('sync.client.entity').pull_update(cr, uid, recover=False, context=context)
483 return {'type': 'ir.actions.act_window_close'}
484
485=== modified file 'sync_client/wizard/sync_wiz_view.xml'
486--- sync_client/wizard/sync_wiz_view.xml 2013-01-25 16:07:17 +0000
487+++ sync_client/wizard/sync_wiz_view.xml 2014-10-14 12:49:38 +0000
488@@ -158,8 +158,8 @@
489 <button type="object" string="Resume All Synchronization Process" name="sync" attrs="{'invisible' : [('state', 'in', ['init', 'corrupted'])]}"/>
490 </group>
491 <group col="2" colspan="3">
492- <button type="object" string="Start All Synchronization In Background" name="sync_threaded" states="init"/>
493- <button type="object" string="Resume All Synchronization In Background" name="sync_threaded" attrs="{'invisible' : [('state', 'in', ['init', 'corrupted'])]}"/>
494+ <button type="object" string="Start All Synchronization In Background" name="sync_manual_threaded" states="init"/>
495+ <button type="object" string="Resume All Synchronization In Background" name="sync_manual_threaded" attrs="{'invisible' : [('state', 'in', ['init', 'corrupted'])]}"/>
496 </group>
497 </group>
498 <separator string="Debug" colspan="4"/>
499@@ -236,4 +236,3 @@
500 <!--
501 vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
502 -->
503-

Subscribers

People subscribed via source and target branches

to all changes: