From 5d7f760a05d3feee54bddc53666daf499ed7edbd Mon Sep 17 00:00:00 2001 From: "olt@tinyerp.com" <> Date: Tue, 23 Oct 2012 09:23:17 +0200 Subject: [PATCH] [FIX] anonymization: add an object to handle migration issues bzr revid: olt@tinyerp.com-20121023072317-zkv1rbf8pt0qnh3g --- addons/anonymization/anonymization.py | 75 ++++++++++++++++----- addons/anonymization/anonymization_view.xml | 1 - 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/addons/anonymization/anonymization.py b/addons/anonymization/anonymization.py index 8834645c460..2326a4184ae 100644 --- a/addons/anonymization/anonymization.py +++ b/addons/anonymization/anonymization.py @@ -32,13 +32,23 @@ import datetime from osv import fields, osv from tools.translate import _ +from itertools import groupby +from operator import itemgetter + FIELD_STATES = [('clear', 'Clear'), ('anonymized', 'Anonymized'), ('not_existing', 'Not Existing')] ANONYMIZATION_STATES = FIELD_STATES + [('unstable', 'Unstable')] +WIZARD_ANONYMIZATION_STATES = [('clear', 'Clear'), ('anonymized', 'Anonymized'), ('unstable', 'Unstable')] ANONYMIZATION_HISTORY_STATE = [('started', 'Started'), ('done', 'Done'), ('in_exception', 'Exception occured')] ANONYMIZATION_DIRECTION = [('clear -> anonymized', 'clear -> anonymized'), ('anonymized -> clear', 'anonymized -> clear')] +def group(lst, cols): + if isinstance(cols, basestring): + cols = [cols] + return dict((k, [v for v in itr]) for k, itr in groupby(sorted(lst, key=itemgetter(*cols)), itemgetter(*cols))) + + class ir_model_fields_anonymization(osv.osv): _name = 'ir.model.fields.anonymization' _rec_name = 'field_id' @@ -207,8 +217,6 @@ class ir_model_fields_anonymization(osv.osv): 'state': lambda *a: 'clear', } -ir_model_fields_anonymization() - class ir_model_fields_anonymization_history(osv.osv): _name = 'ir.model.fields.anonymization.history' @@ -223,8 +231,6 @@ class ir_model_fields_anonymization_history(osv.osv): 'filepath': fields.char(string='File path', size=256, readonly=True), } -ir_model_fields_anonymization_history() - class ir_model_fields_anonymize_wizard(osv.osv_memory): _name = 'ir.model.fields.anonymize.wizard' @@ -250,8 +256,8 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory): 'name': fields.char(size=64, string='File Name'), 'summary': fields.function(_get_summary, type='text', string='Summary'), 'file_export': fields.binary(string='Export'), - 'file_import': fields.binary(string='Import'), - 'state': fields.function(_get_state, string='Status', type='selection', selection=ANONYMIZATION_STATES, readonly=False), + 'file_import': fields.binary(string='Import', help="This is the file created by the anonymization process. It should have the '.pickle' extention."), + 'state': fields.function(_get_state, string='Status', type='selection', selection=WIZARD_ANONYMIZATION_STATES, readonly=False), 'msg': fields.text(string='Message'), } @@ -319,6 +325,7 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory): # clicked in the menu and the fields are already anonymized placeholder.addnext(etree.Element('newline')) placeholder.addnext(etree.Element('field', {'name': 'file_import', 'required': "1"})) + placeholder.addnext(etree.Element('label', {'string': 'Anonymization file'})) eview.remove(placeholder) elif step == 'just_anonymized': # we just ran the anonymization process, we need the file export field @@ -500,7 +507,6 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory): def reverse_anonymize_database(self, cr, uid, ids, context=None): """Set the 'clear' state to defined fields""" - ir_model_fields_anonymization_model = self.pool.get('ir.model.fields.anonymization') anonymization_history_model = self.pool.get('ir.model.fields.anonymization.history') @@ -524,23 +530,46 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory): wizards = self.browse(cr, uid, ids, context=context) for wizard in wizards: if not wizard.file_import: - msg = "It is not possible to reverse the anonymization process without supplying anonymization export file." + msg = "It is not possible to reverse the anonymization process without supplying the anonymization export file." self._raise_after_history_update(cr, uid, history_id, 'Error !', msg) # reverse the anonymization: # load the pickle file content into a data structure: data = pickle.loads(base64.decodestring(wizard.file_import)) + migration_fix_obj = self.pool.get('ir.model.fields.anonymization.migration.fix') + fix_ids = migration_fix_obj.search(cr, uid, [('target_version', '=', '7.0')]) + fixes = migration_fix_obj.read(cr, uid, fix_ids, ['model_name', 'field_name', 'query', 'query_type', 'sequence']) + fixes = group(fixes, ('model_name', 'field_name')) + for line in data: table_name = self.pool.get(line['model_id'])._table - sql = "update %(table)s set %(field)s = %%(value)s where id = %%(id)s" % { - 'table': table_name, - 'field': line['field_id'], - } - cr.execute(sql, { - 'value': line['value'], - 'id': line['id'] - }) + + # check if custom sql exists: + key = (line['model_id'], line['field_id']) + custom_updates = fixes.get(key) + if custom_updates: + custom_updates.sort(itemgetter('sequence')) + queries = [(record['query'], record['query_type']) for record in custom_updates if record['query_type']] + else: + queries = [("update %(table)s set %(field)s = %%(value)s where id = %%(id)s" % { + 'table': table_name, + 'field': line['field_id'], + }, 'sql')] + + for query in queries: + if query[1] == 'sql': + sql = query[0] + cr.execute(sql, { + 'value': line['value'], + 'id': line['id'] + }) + elif query[1] == 'python': + raw_code = query[0] + code = raw_code % line + eval(code) + else: + raise Exception("Unknown query type '%s'. Valid types are: sql, python." % (query['query_type'], )) # update the anonymization fields: ir_model_fields_anonymization_model = self.pool.get('ir.model.fields.anonymization') @@ -589,7 +618,19 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory): res = None return res -ir_model_fields_anonymize_wizard() +class ir_model_fields_anonymization_migration_fix(osv.osv): + _name = 'ir.model.fields.anonymization.migration.fix' + _order = "sequence" + + _columns = { + 'target_version': fields.char('Target Version'), + 'model_name': fields.char('Model'), + 'field_name': fields.char('Field'), + 'query': fields.text('Query'), + 'query_type': fields.selection(string='Query', selection=[('sql', 'sql'), ('python', 'python')]), + 'sequence': fields.integer('Sequence'), + } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/anonymization/anonymization_view.xml b/addons/anonymization/anonymization_view.xml index 1a6c6c355d5..fca112eb266 100644 --- a/addons/anonymization/anonymization_view.xml +++ b/addons/anonymization/anonymization_view.xml @@ -14,7 +14,6 @@