[MIG] anonymization: Migrated to new api.
This commit is contained in:
committed by
Yannick Tivisse
parent
cc57fcba7a
commit
94ba7cd75e
@@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import models
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="anonymization_field_ir_actions_todo_name" model="ir.model.fields.anonymization">
|
||||
@@ -18,5 +18,5 @@
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
FIELD_STATES = [('clear', 'Clear'), ('anonymized', 'Anonymized'), ('not_existing', 'Not Existing'), ('new', 'New')]
|
||||
ANONYMIZATION_HISTORY_STATE = [('started', 'Started'), ('done', 'Done'), ('in_exception', 'Exception occured')]
|
||||
@@ -20,198 +18,138 @@ def group(lst, 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):
|
||||
class IrModelFieldsAnonymization(models.Model):
|
||||
_name = 'ir.model.fields.anonymization'
|
||||
_rec_name = 'field_id'
|
||||
|
||||
_columns = {
|
||||
'model_name': fields.char('Object Name', required=True),
|
||||
'model_id': fields.many2one('ir.model', 'Object', ondelete='set null'),
|
||||
'field_name': fields.char('Field Name', required=True),
|
||||
'field_id': fields.many2one('ir.model.fields', 'Field', ondelete='set null'),
|
||||
'state': fields.selection(selection=FIELD_STATES, String='Status', required=True, readonly=True),
|
||||
}
|
||||
model_name = fields.Char('Object Name', required=True)
|
||||
model_id = fields.Many2one('ir.model', string='Object', ondelete='set null')
|
||||
field_name = fields.Char(required=True)
|
||||
field_id = fields.Many2one('ir.model.fields', string='Field', ondelete='set null')
|
||||
state = fields.Selection(selection=FIELD_STATES, string='Status', required=True, readonly=True, default='clear')
|
||||
|
||||
_sql_constraints = [
|
||||
('model_id_field_id_uniq', 'unique (model_name, field_name)', _("You cannot have two fields with the same name on the same object!")),
|
||||
]
|
||||
|
||||
def _get_global_state(self, cr, uid, context=None):
|
||||
ids = self.search(cr, uid, [('state', '<>', 'not_existing')], context=context)
|
||||
fields = self.browse(cr, uid, ids, context=context)
|
||||
if not len(fields) or len(fields) == len([f for f in fields if f.state == 'clear']):
|
||||
state = 'clear' # all fields are clear
|
||||
elif len(fields) == len([f for f in fields if f.state == 'anonymized']):
|
||||
state = 'anonymized' # all fields are anonymized
|
||||
@api.model
|
||||
def _get_global_state(self):
|
||||
field_ids = self.search([('state', '!=', 'not_existing')])
|
||||
if not field_ids or len(field_ids) == len(field_ids.filtered(lambda field: field.state == "clear")):
|
||||
state = 'clear' # all fields are clear
|
||||
elif len(field_ids) == len(field_ids.filtered(lambda field: field.state == "anonymized")):
|
||||
state = 'anonymized' # all fields are anonymized
|
||||
else:
|
||||
state = 'unstable' # fields are mixed: this should be fixed
|
||||
|
||||
state = 'unstable' # fields are mixed: this should be fixed
|
||||
return state
|
||||
|
||||
def _check_write(self, cr, uid, context=None):
|
||||
@api.model
|
||||
def _check_write(self):
|
||||
"""check that the field is created from the menu and not from an database update
|
||||
otherwise the database update can crash:"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
if context.get('manual'):
|
||||
global_state = self._get_global_state(cr, uid, context=context)
|
||||
if self.env.context.get('manual'):
|
||||
global_state = self._get_global_state()
|
||||
if global_state == 'anonymized':
|
||||
raise UserError(_("The database is currently anonymized, you cannot create, modify or delete fields."))
|
||||
elif global_state == 'unstable':
|
||||
msg = _("The database anonymization is currently in an unstable state. Some fields are anonymized,"
|
||||
" while some fields are not anonymized. You should try to solve this problem before trying to create, write or delete fields.")
|
||||
raise UserError(msg)
|
||||
|
||||
raise UserError(_("The database anonymization is currently in an unstable state. Some fields are anonymized,"
|
||||
" while some fields are not anonymized. You should try to solve this problem before trying to create, write or delete fields."))
|
||||
return True
|
||||
|
||||
def _get_model_and_field_ids(self, cr, uid, vals, context=None):
|
||||
model_and_field_ids = (False, False)
|
||||
@api.model
|
||||
def _get_model_and_field_ids(self, vals):
|
||||
if vals.get('field_name') and vals.get('model_name'):
|
||||
model_id = self.env['ir.model'].search([('model', '=', vals['model_name'])], limit=1).id
|
||||
if model_id:
|
||||
field_id = self.env['ir.model.fields'].search([('name', '=', vals['field_name']), ('model_id', '=', model_id)], limit=1).id
|
||||
if field_id:
|
||||
return (model_id, field_id)
|
||||
return (False, False)
|
||||
|
||||
if 'field_name' in vals and vals['field_name'] and 'model_name' in vals and vals['model_name']:
|
||||
ir_model_fields_obj = self.pool.get('ir.model.fields')
|
||||
ir_model_obj = self.pool.get('ir.model')
|
||||
|
||||
model_ids = ir_model_obj.search(cr, uid, [('model', '=', vals['model_name'])], context=context)
|
||||
if model_ids:
|
||||
field_ids = ir_model_fields_obj.search(cr, uid, [('name', '=', vals['field_name']), ('model_id', '=', model_ids[0])], context=context)
|
||||
if field_ids:
|
||||
field_id = field_ids[0]
|
||||
model_and_field_ids = (model_ids[0], field_id)
|
||||
|
||||
return model_and_field_ids
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# check field state: all should be clear before we can add a new field to anonymize:
|
||||
self._check_write(cr, uid, context=context)
|
||||
|
||||
global_state = self._get_global_state(cr, uid, context=context)
|
||||
|
||||
if 'field_name' in vals and vals['field_name'] and 'model_name' in vals and vals['model_name']:
|
||||
vals['model_id'], vals['field_id'] = self._get_model_and_field_ids(cr, uid, vals, context=context)
|
||||
|
||||
self._check_write()
|
||||
if vals.get('field_name') and vals.get('model_name'):
|
||||
vals['model_id'], vals['field_id'] = self._get_model_and_field_ids(vals)
|
||||
# check not existing fields:
|
||||
if not vals.get('field_id'):
|
||||
vals['state'] = 'not_existing'
|
||||
else:
|
||||
vals['state'] = global_state
|
||||
vals['state'] = self._get_global_state() if vals.get('field_id') else 'not_existing'
|
||||
return super(IrModelFieldsAnonymization, self).create(vals)
|
||||
|
||||
res = super(ir_model_fields_anonymization, self).create(cr, uid, vals, context=context)
|
||||
|
||||
return res
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
# check field state: all should be clear before we can modify a field:
|
||||
if not (len(vals.keys()) == 1 and vals.get('state') == 'clear'):
|
||||
self._check_write(cr, uid, context=context)
|
||||
|
||||
if 'field_name' in vals and vals['field_name'] and 'model_name' in vals and vals['model_name']:
|
||||
vals['model_id'], vals['field_id'] = self._get_model_and_field_ids(cr, uid, vals, context=context)
|
||||
|
||||
if not len(vals.keys()) == 1 and vals.get('state') == 'clear':
|
||||
self._check_write()
|
||||
if vals.get('field_name') and vals.get('model_name'):
|
||||
vals['model_id'], vals['field_id'] = self._get_model_and_field_ids(vals)
|
||||
# check not existing fields:
|
||||
if 'field_id' in vals:
|
||||
if not vals.get('field_id'):
|
||||
if not vals['field_id']:
|
||||
vals['state'] = 'not_existing'
|
||||
else:
|
||||
global_state = self._get_global_state(cr, uid, context)
|
||||
global_state = self._get_global_state()
|
||||
if global_state != 'unstable':
|
||||
vals['state'] = global_state
|
||||
return super(IrModelFieldsAnonymization, self).write(vals)
|
||||
|
||||
res = super(ir_model_fields_anonymization, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
return res
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
# check field state: all should be clear before we can unlink a field:
|
||||
self._check_write(cr, uid, context=context)
|
||||
self._check_write()
|
||||
return super(IrModelFieldsAnonymization, self).unlink()
|
||||
|
||||
res = super(ir_model_fields_anonymization, self).unlink(cr, uid, ids, context=context)
|
||||
return res
|
||||
@api.onchange('model_id')
|
||||
def _onchange_model_id(self):
|
||||
self.field_name = False
|
||||
self.field_id = False
|
||||
self.model_name = self.model_id.model
|
||||
|
||||
def onchange_model_id(self, cr, uid, ids, model_id, context=None):
|
||||
res = {'value': {
|
||||
'field_name': False,
|
||||
'field_id': False,
|
||||
'model_name': False,
|
||||
}}
|
||||
@api.onchange('model_name')
|
||||
def _onchange_model_name(self):
|
||||
self.field_name = False
|
||||
self.field_id = False
|
||||
if self.model_name:
|
||||
self.model_id = self.env['ir.model'].search([('model', '=', self.model_name)], limit=1)
|
||||
else:
|
||||
self.model_id = False
|
||||
|
||||
if model_id:
|
||||
ir_model_obj = self.pool.get('ir.model')
|
||||
model_ids = ir_model_obj.search(cr, uid, [('id', '=', model_id)])
|
||||
model_id = model_ids and model_ids[0] or None
|
||||
model_name = model_id and ir_model_obj.browse(cr, uid, model_id).model or False
|
||||
res['value']['model_name'] = model_name
|
||||
@api.onchange('field_name')
|
||||
def _onchange_field_name(self):
|
||||
if self.field_name and self.model_name:
|
||||
self.field_id = self.env['ir.model.fields'].search([
|
||||
('name', '=', self.field_name), ('model', '=', self.model_name)
|
||||
], limit=1)
|
||||
else:
|
||||
self.field_id = False
|
||||
|
||||
return res
|
||||
|
||||
def onchange_model_name(self, cr, uid, ids, model_name, context=None):
|
||||
res = {'value': {
|
||||
'field_name': False,
|
||||
'field_id': False,
|
||||
'model_id': False,
|
||||
}}
|
||||
|
||||
if model_name:
|
||||
ir_model_obj = self.pool.get('ir.model')
|
||||
model_ids = ir_model_obj.search(cr, uid, [('model', '=', model_name)])
|
||||
model_id = model_ids and model_ids[0] or False
|
||||
res['value']['model_id'] = model_id
|
||||
|
||||
return res
|
||||
|
||||
def onchange_field_name(self, cr, uid, ids, field_name, model_name):
|
||||
res = {'value': {
|
||||
'field_id': False,
|
||||
}}
|
||||
|
||||
if field_name and model_name:
|
||||
ir_model_fields_obj = self.pool.get('ir.model.fields')
|
||||
field_ids = ir_model_fields_obj.search(cr, uid, [('name', '=', field_name), ('model', '=', model_name)])
|
||||
field_id = field_ids and field_ids[0] or False
|
||||
res['value']['field_id'] = field_id
|
||||
|
||||
return res
|
||||
|
||||
def onchange_field_id(self, cr, uid, ids, field_id, model_name):
|
||||
res = {'value': {
|
||||
'field_name': False,
|
||||
}}
|
||||
|
||||
if field_id:
|
||||
ir_model_fields_obj = self.pool.get('ir.model.fields')
|
||||
field = ir_model_fields_obj.browse(cr, uid, field_id)
|
||||
res['value']['field_name'] = field.name
|
||||
|
||||
return res
|
||||
|
||||
_defaults = {
|
||||
'state': lambda *a: 'clear',
|
||||
}
|
||||
@api.onchange('field_id')
|
||||
def _onchange_field_id(self):
|
||||
self.field_name = self.field_id.name
|
||||
|
||||
|
||||
class ir_model_fields_anonymization_history(osv.osv):
|
||||
class IrModelFieldsAnonymizationHistory(models.Model):
|
||||
_name = 'ir.model.fields.anonymization.history'
|
||||
_order = "date desc"
|
||||
|
||||
_columns = {
|
||||
'date': fields.datetime('Date', required=True, readonly=True),
|
||||
'field_ids': fields.many2many('ir.model.fields.anonymization', 'anonymized_field_to_history_rel', 'field_id', 'history_id', 'Fields', readonly=True),
|
||||
'state': fields.selection(selection=ANONYMIZATION_HISTORY_STATE, string='Status', required=True, readonly=True),
|
||||
'direction': fields.selection(selection=ANONYMIZATION_DIRECTION, string='Direction', size=20, required=True, readonly=True),
|
||||
'msg': fields.text('Message', readonly=True),
|
||||
'filepath': fields.char(string='File path', readonly=True),
|
||||
}
|
||||
date = fields.Datetime(required=True, readonly=True)
|
||||
field_ids = fields.Many2many(
|
||||
'ir.model.fields.anonymization', 'anonymized_field_to_history_rel',
|
||||
'field_id', 'history_id', string='Fields', readonly=True
|
||||
)
|
||||
state = fields.Selection(selection=ANONYMIZATION_HISTORY_STATE, string='Status', required=True, readonly=True)
|
||||
direction = fields.Selection(selection=ANONYMIZATION_DIRECTION, required=True, readonly=True)
|
||||
msg = fields.Text('Message', readonly=True)
|
||||
filepath = fields.Char('File path', readonly=True)
|
||||
|
||||
|
||||
class ir_model_fields_anonymization_migration_fix(osv.osv):
|
||||
class IrModelFieldsAnonymizationMigrationFix(models.Model):
|
||||
_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'),
|
||||
}
|
||||
target_version = fields.Char('Target Version')
|
||||
model_name = fields.Char('Model')
|
||||
field_name = fields.Char('Field')
|
||||
query = fields.Text()
|
||||
query_type = fields.Selection(selection=[('sql', 'sql'), ('python', 'python')], string='Query')
|
||||
sequence = fields.Integer()
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- FIELD LIST -->
|
||||
|
||||
<record model="ir.ui.view" id="view_ir_model_fields_anonymization_form">
|
||||
<record id="view_ir_model_fields_anonymization_form" model="ir.ui.view">
|
||||
<field name="name">ir.model.fields.anonymization.form</field>
|
||||
<field name="model">ir.model.fields.anonymization</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Anonymized Field">
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="model_id" on_change="onchange_model_id(model_id)" />
|
||||
<field name="model_name" on_change="onchange_model_name(model_name)" />
|
||||
<field name="model_id" />
|
||||
<field name="model_name" />
|
||||
<field name="field_id"
|
||||
on_change="onchange_field_id(field_id, model_name)"
|
||||
domain="[('model_id','=',model_id), ('ttype', 'not in', ['function', 'binary', 'many2many', 'many2one', 'one2many', 'reference'])]" />
|
||||
<field name="field_name" on_change="onchange_field_name(field_name, model_name)" />
|
||||
<field name="field_name" />
|
||||
<field name="state" />
|
||||
</group>
|
||||
</sheet>
|
||||
@@ -24,7 +22,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_ir_model_fields_anonymization_tree">
|
||||
<record id="view_ir_model_fields_anonymization_tree" model="ir.ui.view">
|
||||
<field name="name">ir.model.fields.anonymization.tree</field>
|
||||
<field name="model">ir.model.fields.anonymization</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -38,7 +36,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_ir_model_fields_anonymization_tree">
|
||||
<record id="action_ir_model_fields_anonymization_tree" model="ir.actions.act_window">
|
||||
<field name="name">Anonymized Fields</field>
|
||||
<field name="res_model">ir.model.fields.anonymization</field>
|
||||
<field name="view_type">form</field>
|
||||
@@ -48,14 +46,14 @@
|
||||
|
||||
<!-- HISTORY -->
|
||||
|
||||
<record model="ir.actions.act_window" id="action_ir_model_fields_anonymization_history_tree">
|
||||
<record id="action_ir_model_fields_anonymization_history_tree" model="ir.actions.act_window">
|
||||
<field name="name">Anonymization History</field>
|
||||
<field name="res_model">ir.model.fields.anonymization.history</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_ir_model_fields_anonymization_history_form">
|
||||
<record id="view_ir_model_fields_anonymization_history_form" model="ir.ui.view">
|
||||
<field name="name">ir.model.fields.anonymization.history.form</field>
|
||||
<field name="model">ir.model.fields.anonymization.history</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -83,7 +81,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_ir_model_fields_anonymization_history_tree">
|
||||
<record id="view_ir_model_fields_anonymization_history_tree" model="ir.ui.view">
|
||||
<field name="name">ir.model.fields.anonymization.history.tree</field>
|
||||
<field name="model">ir.model.fields.anonymization.history</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -115,5 +113,4 @@
|
||||
parent="menu_administration_anonymization"
|
||||
sequence="20" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import anonymize_wizard
|
||||
|
||||
@@ -1,76 +1,55 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from lxml import etree
|
||||
import os
|
||||
import base64
|
||||
import os
|
||||
import random
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
import pickle
|
||||
import random
|
||||
import datetime
|
||||
from openerp.release import version_info
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
|
||||
from lxml import etree
|
||||
from operator import itemgetter
|
||||
from openerp.exceptions import UserError
|
||||
from openerp.addons.anonymization.models.anonymization import group
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.release import version_info
|
||||
from odoo.tools.safe_eval import safe_eval as eval
|
||||
from odoo.addons.anonymization.models.anonymization import group
|
||||
|
||||
WIZARD_ANONYMIZATION_STATES = [('clear', 'Clear'), ('anonymized', 'Anonymized'), ('unstable', 'Unstable')]
|
||||
|
||||
|
||||
class ir_model_fields_anonymize_wizard(osv.osv_memory):
|
||||
class IrModelFieldsAnonymizeWizard(models.TransientModel):
|
||||
_name = 'ir.model.fields.anonymize.wizard'
|
||||
|
||||
def _get_state(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
name = fields.Char('File Name')
|
||||
summary = fields.Text(compute='_compute_summary')
|
||||
file_export = fields.Binary('Export')
|
||||
file_import = fields.Binary('Import',
|
||||
help="This is the file created by the anonymization process. It should have the '.pickle' extention.")
|
||||
state = fields.Selection(compute='_compute_state', string='Status', selection=WIZARD_ANONYMIZATION_STATES)
|
||||
msg = fields.Text('Message')
|
||||
|
||||
state = self._get_state_value(cr, uid, context=None)
|
||||
for id in ids:
|
||||
res[id] = state
|
||||
@api.multi
|
||||
def _compute_summary(self):
|
||||
for anonymize_wizard in self:
|
||||
anonymize_wizard.summary = anonymize_wizard._get_summary_value()
|
||||
|
||||
return res
|
||||
@api.multi
|
||||
def _compute_state(self):
|
||||
for anonymize_wizard in self:
|
||||
anonymize_wizard.state = anonymize_wizard._get_state_value()
|
||||
|
||||
def _get_summary(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
summary = self._get_summary_value(cr, uid, context)
|
||||
for id in ids:
|
||||
res[id] = summary
|
||||
@api.model
|
||||
def _get_state_value(self):
|
||||
return self.env['ir.model.fields.anonymization']._get_global_state()
|
||||
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'name': fields.char(string='File Name'),
|
||||
'summary': fields.function(_get_summary, type='text', string='Summary'),
|
||||
'file_export': fields.binary(string='Export'),
|
||||
'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'),
|
||||
}
|
||||
|
||||
def _get_state_value(self, cr, uid, context=None):
|
||||
state = self.pool.get('ir.model.fields.anonymization')._get_global_state(cr, uid, context=context)
|
||||
return state
|
||||
|
||||
def _get_summary_value(self, cr, uid, context=None):
|
||||
@api.model
|
||||
def _get_summary_value(self):
|
||||
summary = u''
|
||||
anon_field_obj = self.pool.get('ir.model.fields.anonymization')
|
||||
ir_model_fields_obj = self.pool.get('ir.model.fields')
|
||||
|
||||
anon_field_ids = anon_field_obj.search(cr, uid, [('state', '<>', 'not_existing')], context=context)
|
||||
anon_fields = anon_field_obj.browse(cr, uid, anon_field_ids, context=context)
|
||||
|
||||
field_ids = [anon_field.field_id.id for anon_field in anon_fields if anon_field.field_id]
|
||||
fields = ir_model_fields_obj.browse(cr, uid, field_ids, context=context)
|
||||
|
||||
fields_by_id = dict([(f.id, f) for f in fields])
|
||||
|
||||
for anon_field in anon_fields:
|
||||
field = fields_by_id.get(anon_field.field_id.id)
|
||||
|
||||
for anon_field in self.env['ir.model.fields.anonymization'].search([('state', '!=', 'not_existing')]):
|
||||
field = anon_field.field_id
|
||||
values = {
|
||||
'model_name': field.model_id.name,
|
||||
'model_code': field.model_id.model,
|
||||
@@ -79,28 +58,22 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
|
||||
'state': anon_field.state,
|
||||
}
|
||||
summary += u" * %(model_name)s (%(model_code)s) -> %(field_name)s (%(field_code)s): state: (%(state)s)\n" % values
|
||||
|
||||
return summary
|
||||
|
||||
def default_get(self, cr, uid, fields_list, context=None):
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = {}
|
||||
res['name'] = '.pickle'
|
||||
res['summary'] = self._get_summary_value(cr, uid, context)
|
||||
res['state'] = self._get_state_value(cr, uid, context)
|
||||
res['msg'] = _("""Before executing the anonymization process, you should make a backup of your database.""")
|
||||
|
||||
res['summary'] = self._get_summary_value()
|
||||
res['state'] = self._get_state_value()
|
||||
res['msg'] = _("Before executing the anonymization process, you should make a backup of your database.")
|
||||
return res
|
||||
|
||||
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
||||
state = self.pool.get('ir.model.fields.anonymization')._get_global_state(cr, uid, context=context)
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
step = context.get('step', 'new_window')
|
||||
|
||||
res = super(ir_model_fields_anonymize_wizard, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
|
||||
|
||||
@api.model
|
||||
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
|
||||
state = self.env['ir.model.fields.anonymization']._get_global_state()
|
||||
step = self.env.context.get('step', 'new_window')
|
||||
res = super(IrModelFieldsAnonymizeWizard, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
|
||||
eview = etree.fromstring(res['arch'])
|
||||
placeholder = eview.xpath("group[@name='placeholder1']")
|
||||
if len(placeholder):
|
||||
@@ -138,76 +111,64 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
|
||||
for button in buttons:
|
||||
eview.remove(button)
|
||||
# and add a message
|
||||
# and add a message:
|
||||
placeholder.addnext(etree.Element('field', {'name': 'msg', 'colspan': '4', 'nolabel': '1'}))
|
||||
placeholder.addnext(etree.Element('newline'))
|
||||
placeholder.addnext(etree.Element('label', {'string': 'Result'}))
|
||||
# remove the placeholer:
|
||||
eview.remove(placeholder)
|
||||
else:
|
||||
msg = _("The database anonymization is currently in an unstable state. Some fields are anonymized,"
|
||||
" while some fields are not anonymized. You should try to solve this problem before trying to do anything else.")
|
||||
raise UserError(msg)
|
||||
|
||||
raise UserError(_("The database anonymization is currently in an unstable state. Some fields are anonymized,"
|
||||
" while some fields are not anonymized. You should try to solve this problem before trying to do anything else."))
|
||||
res['arch'] = etree.tostring(eview)
|
||||
|
||||
return res
|
||||
|
||||
def _raise_after_history_update(self, cr, uid, history_id, error_type, error_msg):
|
||||
self.pool.get('ir.model.fields.anonymization.history').write(cr, uid, history_id, {
|
||||
def _raise_after_history_update(self, history, error_type, error_msg):
|
||||
history.write({
|
||||
'state': 'in_exception',
|
||||
'msg': error_msg,
|
||||
})
|
||||
raise UserError('%s: %s' % (error_type, error_msg))
|
||||
|
||||
def anonymize_database(self, cr, uid, ids, context=None):
|
||||
@api.multi
|
||||
def anonymize_database(self):
|
||||
"""Sets the 'anonymized' state to defined fields"""
|
||||
self.ensure_one()
|
||||
|
||||
# create a new history record:
|
||||
anonymization_history_model = self.pool.get('ir.model.fields.anonymization.history')
|
||||
|
||||
vals = {
|
||||
'date': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
history = self.env['ir.model.fields.anonymization.history'].create({
|
||||
'date': fields.Datetime.now(),
|
||||
'state': 'started',
|
||||
'direction': 'clear -> anonymized',
|
||||
}
|
||||
history_id = anonymization_history_model.create(cr, uid, vals)
|
||||
'direction': 'clear -> anonymized'
|
||||
})
|
||||
|
||||
# check that all the defined fields are in the 'clear' state
|
||||
state = self.pool.get('ir.model.fields.anonymization')._get_global_state(cr, uid, context=context)
|
||||
state = self.env['ir.model.fields.anonymization']._get_global_state()
|
||||
if state == 'anonymized':
|
||||
self._raise_after_history_update(cr, uid, history_id, _('Error !'), _("The database is currently anonymized, you cannot anonymize it again."))
|
||||
self._raise_after_history_update(history, _('Error !'), _("The database is currently anonymized, you cannot anonymize it again."))
|
||||
elif state == 'unstable':
|
||||
msg = _("The database anonymization is currently in an unstable state. Some fields are anonymized,"
|
||||
" while some fields are not anonymized. You should try to solve this problem before trying to do anything.")
|
||||
self._raise_after_history_update(cr, uid, history_id, 'Error !', msg)
|
||||
self._raise_after_history_update(history, _('Error !'), _("The database anonymization is currently in an unstable state. Some fields are anonymized,"
|
||||
" while some fields are not anonymized. You should try to solve this problem before trying to do anything."))
|
||||
|
||||
# do the anonymization:
|
||||
dirpath = os.environ.get('HOME') or os.getcwd()
|
||||
rel_filepath = 'field_anonymization_%s_%s.pickle' % (cr.dbname, history_id)
|
||||
rel_filepath = 'field_anonymization_%s_%s.pickle' % (self.env.cr.dbname, history.id)
|
||||
abs_filepath = os.path.abspath(os.path.join(dirpath, rel_filepath))
|
||||
|
||||
ir_model_fields_anonymization_model = self.pool.get('ir.model.fields.anonymization')
|
||||
field_ids = ir_model_fields_anonymization_model.search(cr, uid, [('state', '<>', 'not_existing')], context=context)
|
||||
fields = ir_model_fields_anonymization_model.browse(cr, uid, field_ids, context=context)
|
||||
|
||||
if not fields:
|
||||
msg = "No fields are going to be anonymized."
|
||||
self._raise_after_history_update(cr, uid, history_id, 'Error !', msg)
|
||||
ano_fields = self.env['ir.model.fields.anonymization'].search([('state', '!=', 'not_existing')])
|
||||
if not ano_fields:
|
||||
self._raise_after_history_update(history, _('Error !'), _("No fields are going to be anonymized."))
|
||||
|
||||
data = []
|
||||
|
||||
for field in fields:
|
||||
for field in ano_fields:
|
||||
model_name = field.model_id.model
|
||||
field_name = field.field_id.name
|
||||
field_type = field.field_id.ttype
|
||||
table_name = self.pool[model_name]._table
|
||||
table_name = self.env[model_name]._table
|
||||
|
||||
# get the current value
|
||||
sql = "select id, %s from %s" % (field_name, table_name)
|
||||
cr.execute(sql)
|
||||
records = cr.dictfetchall()
|
||||
for record in records:
|
||||
self.env.cr.execute("select id, %s from %s" % (field_name, table_name))
|
||||
for record in self.env.cr.dictfetchall():
|
||||
data.append({"model_id": model_name, "field_id": field_name, "id": record['id'], "value": record[field_name]})
|
||||
|
||||
# anonymize the value:
|
||||
@@ -215,13 +176,13 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
|
||||
|
||||
sid = str(record['id'])
|
||||
if field_type == 'char':
|
||||
anonymized_value = 'xxx'+sid
|
||||
anonymized_value = 'xxx' + sid
|
||||
elif field_type == 'selection':
|
||||
anonymized_value = 'xxx'+sid
|
||||
anonymized_value = 'xxx' + sid
|
||||
elif field_type == 'text':
|
||||
anonymized_value = 'xxx'+sid
|
||||
anonymized_value = 'xxx' + sid
|
||||
elif field_type == 'html':
|
||||
anonymized_value = 'xxx'+sid
|
||||
anonymized_value = 'xxx' + sid
|
||||
elif field_type == 'boolean':
|
||||
anonymized_value = random.choice([True, False])
|
||||
elif field_type == 'date':
|
||||
@@ -232,18 +193,17 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
|
||||
anonymized_value = 0.0
|
||||
elif field_type == 'integer':
|
||||
anonymized_value = 0
|
||||
elif field_type in ['binary', 'many2many', 'many2one', 'one2many', 'reference']: # cannot anonymize these kind of fields
|
||||
msg = _("Cannot anonymize fields of these types: binary, many2many, many2one, one2many, reference.")
|
||||
self._raise_after_history_update(cr, uid, history_id, 'Error !', msg)
|
||||
elif field_type in ['binary', 'many2many', 'many2one', 'one2many', 'reference']: # cannot anonymize these kind of fields
|
||||
self._raise_after_history_update(history, _('Error !'), _("Cannot anonymize fields of these types: binary, many2many, many2one, one2many, reference."))
|
||||
|
||||
if anonymized_value is None:
|
||||
self._raise_after_history_update(cr, uid, history_id, _('Error !'), _("Anonymized value can not be empty."))
|
||||
self._raise_after_history_update(history, _('Error !'), _("Anonymized value can not be empty."))
|
||||
|
||||
sql = "update %(table)s set %(field)s = %%(anonymized_value)s where id = %%(id)s" % {
|
||||
'table': table_name,
|
||||
'field': field_name,
|
||||
}
|
||||
cr.execute(sql, {
|
||||
self.env.cr.execute(sql, {
|
||||
'anonymized_value': anonymized_value,
|
||||
'id': record['id']
|
||||
})
|
||||
@@ -253,155 +213,126 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
|
||||
pickle.dump(data, fn, pickle.HIGHEST_PROTOCOL)
|
||||
|
||||
# update the anonymization fields:
|
||||
values = {
|
||||
'state': 'anonymized',
|
||||
}
|
||||
ir_model_fields_anonymization_model.write(cr, uid, field_ids, values, context=context)
|
||||
ano_fields.write({'state': 'anonymized'})
|
||||
|
||||
# add a result message in the wizard:
|
||||
msgs = ["Anonymization successful.",
|
||||
"",
|
||||
"Donot forget to save the resulting file to a safe place because you will not be able to revert the anonymization without this file.",
|
||||
"",
|
||||
"This file is also stored in the %s directory. The absolute file path is: %s.",
|
||||
]
|
||||
"",
|
||||
"Donot forget to save the resulting file to a safe place because you will not be able to revert the anonymization without this file.",
|
||||
"",
|
||||
"This file is also stored in the %s directory. The absolute file path is: %s."
|
||||
]
|
||||
msg = '\n'.join(msgs) % (dirpath, abs_filepath)
|
||||
|
||||
fn = open(abs_filepath, 'r')
|
||||
|
||||
self.write(cr, uid, ids, {
|
||||
self.write({
|
||||
'msg': msg,
|
||||
'file_export': base64.encodestring(fn.read()),
|
||||
})
|
||||
fn.close()
|
||||
|
||||
# update the history record:
|
||||
anonymization_history_model.write(cr, uid, history_id, {
|
||||
'field_ids': [[6, 0, field_ids]],
|
||||
history.write({
|
||||
'field_ids': [[6, 0, ano_fields.ids]],
|
||||
'msg': msg,
|
||||
'filepath': abs_filepath,
|
||||
'state': 'done',
|
||||
})
|
||||
|
||||
# handle the view:
|
||||
view_id = self.pool['ir.model.data'].xmlid_to_res_id(
|
||||
cr, uid, 'anonymization.view_ir_model_fields_anonymize_wizard_form'
|
||||
)
|
||||
|
||||
return {
|
||||
'res_id': ids[0],
|
||||
'view_id': [view_id],
|
||||
'res_id': self.id,
|
||||
'view_id': self.env.ref('anonymization.view_ir_model_fields_anonymize_wizard_form').ids,
|
||||
'view_type': 'form',
|
||||
"view_mode": 'form',
|
||||
'res_model': 'ir.model.fields.anonymize.wizard',
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': {'step': 'just_anonymized'},
|
||||
'target': 'new'
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def reverse_anonymize_database(self):
|
||||
"""Set the 'clear' state to defined fields"""
|
||||
self.ensure_one()
|
||||
IrModelFieldsAnonymization = self.env['ir.model.fields.anonymization']
|
||||
|
||||
# create a new history record:
|
||||
history = self.env['ir.model.fields.anonymization.history'].create({
|
||||
'date': fields.Datetime.now(),
|
||||
'state': 'started',
|
||||
'direction': 'anonymized -> clear'
|
||||
})
|
||||
|
||||
# check that all the defined fields are in the 'anonymized' state
|
||||
state = IrModelFieldsAnonymization._get_global_state()
|
||||
if state == 'clear':
|
||||
raise UserError(_("The database is not currently anonymized, you cannot reverse the anonymization."))
|
||||
elif state == 'unstable':
|
||||
raise UserError(_("The database anonymization is currently in an unstable state. Some fields are anonymized,"
|
||||
" while some fields are not anonymized. You should try to solve this problem before trying to do anything."))
|
||||
|
||||
if not self.file_import:
|
||||
raise UserError('%s: %s' % (_('Error !'), _("It is not possible to reverse the anonymization process without supplying the anonymization export file.")))
|
||||
|
||||
# reverse the anonymization:
|
||||
# load the pickle file content into a data structure:
|
||||
data = pickle.loads(base64.decodestring(self.file_import))
|
||||
|
||||
fixes = self.env['ir.model.fields.anonymization.migration.fix'].search_read([
|
||||
('target_version', '=', '.'.join(map(str, version_info[:2])))
|
||||
], ['model_name', 'field_name', 'query', 'query_type', 'sequence'])
|
||||
fixes = group(fixes, ('model_name', 'field_name'))
|
||||
|
||||
for line in data:
|
||||
queries = []
|
||||
table_name = self.env[line['model_id']]._table if line['model_id'] in self.env else None
|
||||
|
||||
# check if custom sql exists:
|
||||
key = (line['model_id'], line['field_id'])
|
||||
custom_updates = fixes.get(key)
|
||||
if custom_updates:
|
||||
custom_updates.sort(key=itemgetter('sequence'))
|
||||
queries = [(record['query'], record['query_type']) for record in custom_updates if record['query_type']]
|
||||
elif table_name:
|
||||
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':
|
||||
self.env.cr.execute(query[0], {
|
||||
'value': line['value'],
|
||||
'id': line['id']
|
||||
})
|
||||
elif query[1] == 'python':
|
||||
eval(query[0] % line)
|
||||
else:
|
||||
raise Exception("Unknown query type '%s'. Valid types are: sql, python." % (query['query_type'], ))
|
||||
|
||||
# update the anonymization fields:
|
||||
ano_fields = IrModelFieldsAnonymization.search([('state', '!=', 'not_existing')])
|
||||
ano_fields.write({'state': 'clear'})
|
||||
|
||||
# add a result message in the wizard:
|
||||
self.msg = '\n'.join(["Successfully reversed the anonymization.", ""])
|
||||
|
||||
# update the history record:
|
||||
history.write({
|
||||
'field_ids': [[6, 0, ano_fields.ids]],
|
||||
'msg': self.msg,
|
||||
'filepath': False,
|
||||
'state': 'done'
|
||||
})
|
||||
|
||||
return {
|
||||
'res_id': self.id,
|
||||
'view_id': self.env.ref('anonymization.view_ir_model_fields_anonymize_wizard_form').ids,
|
||||
'view_type': 'form',
|
||||
"view_mode": 'form',
|
||||
'res_model': 'ir.model.fields.anonymize.wizard',
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': {'step': 'just_anonymized'},
|
||||
'target':'new',
|
||||
}
|
||||
|
||||
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')
|
||||
|
||||
# create a new history record:
|
||||
vals = {
|
||||
'date': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'state': 'started',
|
||||
'direction': 'anonymized -> clear',
|
||||
}
|
||||
history_id = anonymization_history_model.create(cr, uid, vals)
|
||||
|
||||
# check that all the defined fields are in the 'anonymized' state
|
||||
state = ir_model_fields_anonymization_model._get_global_state(cr, uid, context=context)
|
||||
if state == 'clear':
|
||||
raise UserError(_("The database is not currently anonymized, you cannot reverse the anonymization."))
|
||||
elif state == 'unstable':
|
||||
msg = _("The database anonymization is currently in an unstable state. Some fields are anonymized,"
|
||||
" while some fields are not anonymized. You should try to solve this problem before trying to do anything.")
|
||||
raise UserError(msg)
|
||||
|
||||
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 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', '=', '.'.join(map(str, version_info[:2])))])
|
||||
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:
|
||||
queries = []
|
||||
table_name = self.pool[line['model_id']]._table if line['model_id'] in self.pool else None
|
||||
|
||||
# check if custom sql exists:
|
||||
key = (line['model_id'], line['field_id'])
|
||||
custom_updates = fixes.get(key)
|
||||
if custom_updates:
|
||||
custom_updates.sort(key=itemgetter('sequence'))
|
||||
queries = [(record['query'], record['query_type']) for record in custom_updates if record['query_type']]
|
||||
elif table_name:
|
||||
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')
|
||||
field_ids = ir_model_fields_anonymization_model.search(cr, uid, [('state', '<>', 'not_existing')], context=context)
|
||||
values = {
|
||||
'state': 'clear',
|
||||
}
|
||||
ir_model_fields_anonymization_model.write(cr, uid, field_ids, values, context=context)
|
||||
|
||||
# add a result message in the wizard:
|
||||
msg = '\n'.join(["Successfully reversed the anonymization.",
|
||||
"",
|
||||
])
|
||||
|
||||
self.write(cr, uid, ids, {'msg': msg})
|
||||
|
||||
# update the history record:
|
||||
anonymization_history_model.write(cr, uid, history_id, {
|
||||
'field_ids': [[6, 0, field_ids]],
|
||||
'msg': msg,
|
||||
'filepath': False,
|
||||
'state': 'done',
|
||||
})
|
||||
|
||||
# handle the view:
|
||||
view_id = self.pool['ir.model.data'].xmlid_to_res_id(
|
||||
cr, uid, 'anonymization.view_ir_model_fields_anonymize_wizard_form'
|
||||
)
|
||||
|
||||
|
||||
return {
|
||||
'res_id': ids[0],
|
||||
'view_id': [view_id],
|
||||
'view_type': 'form',
|
||||
"view_mode": 'form',
|
||||
'res_model': 'ir.model.fields.anonymize.wizard',
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': {'step': 'just_desanonymized'},
|
||||
'target':'new',
|
||||
'context': {'step': 'just_desanonymized'},
|
||||
'target': 'new'
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="view_ir_model_fields_anonymize_wizard_form">
|
||||
<record id="view_ir_model_fields_anonymize_wizard_form" model="ir.ui.view">
|
||||
<field name="name">ir.model.fields.anonymize.wizard.form</field>
|
||||
<field name="model">ir.model.fields.anonymize.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -27,7 +27,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_ir_model_fields_anonymize_wizard">
|
||||
<record id="action_ir_model_fields_anonymize_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Anonymize Database</field>
|
||||
<field name="res_model">ir.model.fields.anonymize.wizard</field>
|
||||
<field name="target">new</field>
|
||||
@@ -41,4 +41,4 @@
|
||||
parent="anonymization.menu_administration_anonymization"
|
||||
sequence="30" />
|
||||
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user