[ADD] Anonymization module

bzr revid: nel@tinyerp.com-20110107153106-6visyxwb8i21q262
This commit is contained in:
nel@tinyerp.com 2011-01-07 16:31:06 +01:00
parent 8edba174ce
commit 4c3daf0915
9 changed files with 1306 additions and 0 deletions

View File

@ -0,0 +1,25 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import anonymization
import wizard

View File

@ -0,0 +1,48 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'Database anonymization module',
'version': '1.0',
'category': 'Tools',
'description': """
This module allows you to anonymize a database.
""",
'author': 'OpenERP sa',
'website': 'http://www.openerp.com',
'depends': ['base'],
'init_xml': [],
'update_xml': [],
'demo_xml': [
'anonymization_demo.xml',
],
'data': [
'ir.model.fields.anonymization.csv',
'security/ir.model.access.csv',
'anonymization_view.xml',
],
'installable': True,
'active': False,
'certificate': '00719010980872226045',
}

View File

@ -0,0 +1,594 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from lxml import etree
import os
import base64
try:
import cPickle as pickle
except ImportError:
import pickle
import random
import datetime
import netsvc
import pooler, tools
from osv import fields, osv
from tools.translate import _
FIELD_STATES = [('clear', 'Clear'), ('anonymized', 'Anonymized'), ('not_existing', 'Not Existing')]
ANONYMIZATION_STATES = FIELD_STATES + [('unstable', 'Unstable')]
ANONYMIZATION_HISTORY_STATE = [('started', 'Started'), ('done', 'Done'), ('in_exception', 'Exception occured')]
ANONYMIZATION_DIRECTION = [('clear -> anonymized', 'clear -> anonymized'), ('anonymized -> clear', 'anonymized -> clear')]
class ir_model_fields_anonymization(osv.osv):
_name = 'ir.model.fields.anonymization'
_rec_name = 'field_id'
_columns = {
'model_name': fields.char('Object Name', size=128, required=True),
'model_id': fields.many2one('ir.model', 'Object', ondelete='set null'),
'field_name': fields.char('Field Name', size=128, required=True),
'field_id': fields.many2one('ir.model.fields', 'Field', ondelete='set null'),
'state': fields.selection(selection=FIELD_STATES, String='State', required=True, readonly=True),
}
_sql_constraints = [
('model_id_field_id_uniq', 'unique (model_name, field_name)', _("You cannot have two records having the same model and the same field")),
]
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
else:
state = 'unstable' # fields are mixed: this should be fixed
return state
def _check_write(self, cr, uid, context=None):
# check that the field is created from the menu and not from an database update
# otherwise the database update can crash:
if context.get('manual'):
global_state = self._get_global_state(cr, uid, context=context)
if global_state == 'anonymized':
raise osv.except_osv('Error !', "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 osv.except_osv('Error !', msg)
return True
def _get_model_and_field_ids(self, cr, uid, vals, context=None):
model_and_field_ids = (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):
# check field state: all should be clear before we can add a new field to anonymize:
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)
# check not existing fields:
if not vals.get('field_id'):
vals['state'] = 'not_existing'
res = super(ir_model_fields_anonymization, self).create(cr, uid, vals, context=context)
return res
def write(self, cr, uid, ids, vals, context=None):
# 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)
# check not existing fields:
if 'field_id' in vals:
if not vals.get('field_id'):
vals['state'] = 'not_existing'
else:
global_state = self._get_global_state(cr, uid, context)
if global_state != 'unstable':
vals['state'] = global_state
res = super(ir_model_fields_anonymization, self).write(cr, uid, ids, vals, context=context)
return res
def unlink(self, cr, uid, ids, context=None):
# check field state: all should be clear before we can unlink a field:
self._check_write(cr, uid, context=context)
res = super(ir_model_fields_anonymization, self).unlink(cr, uid, ids, context=context)
return res
def onchange_model_id(self, cr, uid, ids, model_id, context=None):
res = {'value': {
'field_name': False,
'field_id': False,
'model_name': 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
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',
}
ir_model_fields_anonymization()
class ir_model_fields_anonymization_history(osv.osv):
_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='State', required=True, readonly=True),
'direction': fields.selection(selection=ANONYMIZATION_DIRECTION, string='Direction', required=True, readonly=True),
'msg': fields.text('Message', readonly=True),
'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'
def _get_state(self, cr, uid, ids, name, arg, context=None):
res = {}
state = self._get_state_value(cr, uid, context=None)
for id in ids:
res[id] = state
return res
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
return res
_columns = {
'name': fields.char(size='64', string='File Name'),
'summary': fields.function(_get_summary, method=True, type='text', string='Summary'),
'file_export': fields.binary(string='Export'),
'file_import': fields.binary(string='Import'),
'state': fields.function(_get_state, method=True, string='State', type='selection', selection=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):
summary = u''
anon_field_obj = self.pool.get('ir.model.fields.anonymization')
ir_model_obj = self.pool.get('ir.model')
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)
values = {
'model_name': field.model_id.name,
'model_code': field.model_id.model,
'field_code': field.name,
'field_name': field.field_description,
'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):
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."""
return res
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, *args, **kwargs):
state = self.pool.get('ir.model.fields.anonymization')._get_global_state(cr, uid, context=context)
step = context.get('step', 'new_window')
res = super(ir_model_fields_anonymize_wizard, self).fields_view_get(cr, uid, view_id, view_type, context, *args, **kwargs)
eview = etree.fromstring(res['arch'])
placeholder = eview.xpath("group[@name='placeholder1']")
placeholder = len(placeholder) and placeholder[0] or None
if placeholder:
if step == 'new_window' and state == 'clear':
# clicked in the menu and the fields are not anonymized: warn the admin that backuping the db is very important
placeholder.addnext(etree.Element('field', {'name': 'msg', 'colspan': '4', 'nolabel': '1'}))
placeholder.addnext(etree.Element('newline'))
placeholder.addnext(etree.Element('label', {'string': 'Warning'}))
eview.remove(placeholder)
elif step == 'new_window' and state == 'anonymized':
# 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"}))
eview.remove(placeholder)
elif step == 'just_anonymized':
# we just ran the anonymization process, we need the file export field
placeholder.addnext(etree.Element('newline'))
placeholder.addnext(etree.Element('field', {'name': 'file_export'}))
# we need to remove the button:
buttons = eview.xpath("button")
for button in buttons:
eview.remove(button)
# 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)
elif step == 'just_desanonymized':
# we just reversed the anonymization process, we don't need any field
# we need to remove the button
buttons = eview.xpath("button")
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:
from olilib.openerp import Terp, ppt, pst
import pydb; pydb.debugger(['set listsize 40'])
print
# unstable ?
raise
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, {
'state': 'in_exception',
'msg': error_msg,
})
raise osv.except_osv(error_type, error_msg)
def anonymize_database(self,cr, uid, ids, context=None):
"""Sets the 'anonymized' state to defined fields"""
# 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'),
'state': 'started',
'direction': 'clear -> anonymized',
}
history_id = anonymization_history_model.create(cr, uid, vals)
# 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)
if state == 'anonymized':
self._raise_after_history_update(cr, uid, history_id, '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)
# do the anonymization:
dirpath = os.environ.get('HOME') or os.getcwd()
rel_filepath = 'field_anonymization_%s_%s.pickle' % (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)
data = []
for field in fields:
model_name = field.model_id.model
field_name = field.field_id.name
field_type = field.field_id.ttype
table_name = self.pool.get(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:
data.append({"model_id": model_name, "field_id": field_name, "id": record['id'], "value": record[field_name]})
# anonymize the value:
anonymized_value = None
sid = str(record['id'])
if field_type == 'char':
anonymized_value = 'xxx'+sid
elif field_type == 'selection':
anonymized_value = 'xxx'+sid
elif field_type == 'text':
anonymized_value = 'xxx'+sid
elif field_type == 'boolean':
anonymized_value = random.choice([True, False])
elif field_type == 'date':
anonymized_value = '2011-11-11'
elif field_type == 'datetime':
anonymized_value = '2011-11-11 11:11:11'
elif field_type == 'float':
if record[field_name] > 0:
anonymized_value = 1.0
elif record[field_name] < 0:
anonymized_value = -1.0
else:
anonymized_value = 0.0
elif field_type == 'integer':
anonymized_value = 1
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)
if anonymized_value is None:
self._raise_after_history_update(cr, uid, history_id, 'Error !', "Anonymized value is None. This cannot happens.")
sql = "update %(table)s set %(field)s = %%(anonymized_value)s where id = %%(id)s" % {
'table': table_name,
'field': field_name,
}
cr.execute(sql, {
'anonymized_value': anonymized_value,
'id': record['id']
})
# save pickle:
fn = open(abs_filepath, 'w')
pickle.dump(data, fn, pickle.HIGHEST_PROTOCOL)
# update the anonymization fields:
values = {
'state': 'anonymized',
}
res = ir_model_fields_anonymization_model.write(cr, uid, field_ids, values, context=context)
# add a result message in the wizard:
msgs = ["Anonymization successful.",
"",
"Don't 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, {
'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]],
'msg': msg,
'filepath': abs_filepath,
'state': 'done',
})
# handle the view:
view_id = self._id_get(cr, uid, 'ir.ui.view', 'view_ir_model_fields_anonymize_wizard_form', 'anonymization')
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_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 osv.except_osv('Error !', "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 osv.except_osv('Error !', msg)
wizards = self.browse(cr, uid, ids, context=context)
for wizard in wizards:
if not wizard.file_import:
msg = "The anonymization export file was not supplied. It is not possible to reverse the anonymization process without this 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))
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']
})
# 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',
}
res = 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._id_get(cr, uid, 'ir.ui.view', 'view_ir_model_fields_anonymize_wizard_form', 'anonymization')
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',
}
def _id_get(self, cr, uid, model, id_str, mod):
if '.' in id_str:
mod, id_str = id_str.split('.')
try:
idn = self.pool.get('ir.model.data')._get_id(cr, uid, mod, id_str)
res = int(self.pool.get('ir.model.data').read(cr, uid, [idn], ['res_id'])[0]['res_id'])
except Exception, e:
res = None
return res
ir_model_fields_anonymize_wizard()

View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<record id="anonymization_field_ir_actions_todo_name" model="ir.model.fields.anonymization">
<field name="model_name">ir.actions.todo</field>
<field name="field_name">name</field>
</record>
<record id="anonymization_field_a_non_existing_field_in_an_existing_model" model="ir.model.fields.anonymization">
<field name="model_name">res.partner</field>
<field name="field_name">a_non_existing_field</field>
</record>
<record id="anonymization_field_a_non_existing_field_in_a_non_existing_model" model="ir.model.fields.anonymization">
<field name="model_name">a.non.existing.model</field>
<field name="field_name">a_non_existing_field</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,173 @@
<?xml version="1.0" ?>
<openerp>
<data>
<!-- FIELD LIST -->
<record model="ir.ui.view" id="view_ir_model_fields_anonymization_form">
<field name="name">ir.model.fields.anonymization.form</field>
<field name="model">ir.model.fields.anonymization</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Anonymized Field">
<group colspan="4" col="8">
<field name="model_id" select="1" on_change="onchange_model_id(model_id)" />
<field name="model_name" select="1" on_change="onchange_model_name(model_name)" />
<field name="field_id"
select="1"
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" select="1" on_change="onchange_field_name(field_name, model_name)" />
</group>
<field name="state" />
</form>
</field>
</record>
<record model="ir.ui.view" id="view_ir_model_fields_anonymization_tree">
<field name="name">ir.model.fields.anonymization.tree</field>
<field name="model">ir.model.fields.anonymization</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Anonymized Fields">
<field name="model_id" />
<field name="model_name" />
<field name="field_id" />
<field name="field_name" />
<field name="state" />
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_ir_model_fields_anonymization_tree">
<field name="name">Anonymized Fields</field>
<field name="res_model">ir.model.fields.anonymization</field>
<field name="view_type">form</field>
<field name="context">{'manual': True}</field>
<field name="view_mode">tree,form</field>
</record>
<!-- ANONYMIZE WIZARD -->
<!-- VIEW 1 -->
<record model="ir.ui.view" id="view_ir_model_fields_anonymize_wizard_form">
<field name="name">ir.model.fields.anonymize.wizard.form</field>
<field name="model">ir.model.fields.anonymize.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Database Anonymization">
<label string="Summary" />
<newline />
<group colspan="4" col="4">
<field name="summary" nolabel="1" readonly="0" width="400" />
</group>
<newline />
<group name="placeholder1">
<field name="file_export" />
<field name="file_import" />
<field name="msg" />
</group>
<button name="anonymize_database"
string="Anonymize Database"
type="object"
states="clear" />
<button name="reverse_anonymize_database"
string="Reverse the Database Anonymization"
type="object"
states="anonymized" />
<newline />
<field name="state" />
</form>
</field>
</record>
<!-- ACTION -->
<record model="ir.actions.act_window" id="action_ir_model_fields_anonymize_wizard">
<field name="name">Anonymize Database</field>
<field name="res_model">ir.model.fields.anonymize.wizard</field>
<field name="target">new</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
</record>
<!-- HISTORY -->
<record model="ir.actions.act_window" id="action_ir_model_fields_anonymization_history_tree">
<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">
<field name="name">ir.model.fields.anonymization.history.form</field>
<field name="model">ir.model.fields.anonymization.history</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Anonymization History">
<group colspan="4" col="16">
<field name="date" select="1" colspan="1" />
<field name="state" select="1" colspan="1" />
<field name="filepath" colspan="7" />
<field name="direction" colspan="3" />
</group>
<group colspan="4" col="2">
<label string="Message" />
<field name="msg" nolabel="1" colspan="4" readonly="0" height="150" />
</group>
<group colspan="4" col="2">
<label string="Fields" />
<field name="field_ids" nolabel="1" colspan="4" height="300">
<tree>
<field name="model_id" />
<field name="field_id" />
</tree>
</field>
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_ir_model_fields_anonymization_history_tree">
<field name="name">ir.model.fields.anonymization.history.tree</field>
<field name="model">ir.model.fields.anonymization.history</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Anonymization History">
<field name="date" />
<field name="state" />
<field name="filepath" />
<field name="direction" />
</tree>
</field>
</record>
<!-- MENUS -->
<menuitem id="menu_administration_anonymization"
name="Database anonymization"
parent="base.menu_administration"
sequence="30" />
<menuitem id="menu_administration_anonymization_history"
name="Anonymization History"
action="action_ir_model_fields_anonymization_history_tree"
parent="menu_administration_anonymization"
sequence="10" />
<menuitem id="menu_administration_anonymization_fields"
name="Anonymized Fields"
action="action_ir_model_fields_anonymization_tree"
parent="menu_administration_anonymization"
sequence="20" />
<menuitem id="menu_administration_anonymization_wizard"
action="action_ir_model_fields_anonymize_wizard"
name="Anonymize database"
parent="menu_administration_anonymization"
sequence="30" />
</data>
</openerp>

View File

@ -0,0 +1,201 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * anonymization
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2010-12-10 14:48:44+0000\n"
"PO-Revision-Date: 2010-12-10 15:49+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
#. module: anonymization
#: model:ir.model,name:anonymization.model_ir_model_fields_anonymize_wizard
msgid "ir.model.fields.anonymize.wizard"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization,field_id:0
msgid "Field"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization.history,state:0
#: field:ir.model.fields.anonymize.wizard,state:0
msgid "State"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymize.wizard,file_import:0
msgid "Import"
msgstr ""
#. module: anonymization
#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization
msgid "ir.model.fields.anonymization"
msgstr ""
#. module: anonymization
#: model:ir.module.module,shortdesc:anonymization.module_meta_information
msgid "Database anonymization module"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization.history,direction:0
msgid "Direction"
msgstr ""
#. module: anonymization
#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_tree
#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_fields
msgid "Anonymized Fields"
msgstr ""
#. module: anonymization
#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization
msgid "Database anonymization"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,direction:0
msgid "clear -> anonymized"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization,state:0
#: selection:ir.model.fields.anonymize.wizard,state:0
msgid "Anonymized"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization,state:0
msgid "unknown"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization,model_id:0
msgid "Object"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization.history,filepath:0
msgid "File path"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization.history,date:0
msgid "Date"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymize.wizard,file_export:0
msgid "Export"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymize.wizard:0
msgid "Reverse the Database Anonymization"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymize.wizard:0
msgid "Database Anonymization"
msgstr ""
#. module: anonymization
#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_wizard
msgid "Anonymize database"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymization.history:0
#: field:ir.model.fields.anonymization.history,field_ids:0
msgid "Fields"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization,state:0
#: selection:ir.model.fields.anonymize.wizard,state:0
msgid "Clear"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymize.wizard:0
#: field:ir.model.fields.anonymize.wizard,summary:0
msgid "Summary"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymization:0
msgid "Anonymized Field"
msgstr ""
#. module: anonymization
#: model:ir.module.module,description:anonymization.module_meta_information
msgid ""
"\n"
"This module allows you to anonymize a database.\n"
" "
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymize.wizard,state:0
msgid "Unstable"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,state:0
msgid "Exception occured"
msgstr ""
#. module: anonymization
#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_history_tree
#: view:ir.model.fields.anonymization.history:0
#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_history
msgid "Anonymization History"
msgstr ""
#. module: anonymization
#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization_history
msgid "ir.model.fields.anonymization.history"
msgstr ""
#. module: anonymization
#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymize_wizard
#: view:ir.model.fields.anonymize.wizard:0
msgid "Anonymize Database"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymize.wizard,name:0
msgid "File Name"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,direction:0
msgid "anonymized -> clear"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,state:0
msgid "Started"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,state:0
msgid "Done"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymization.history:0
#: field:ir.model.fields.anonymization.history,msg:0
#: field:ir.model.fields.anonymize.wizard,msg:0
msgid "Message"
msgstr ""

View File

@ -0,0 +1,201 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * anonymization
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2010-12-10 14:48:44+0000\n"
"PO-Revision-Date: 2010-12-10 15:49+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
#. module: anonymization
#: model:ir.model,name:anonymization.model_ir_model_fields_anonymize_wizard
msgid "ir.model.fields.anonymize.wizard"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization,field_id:0
msgid "Field"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization.history,state:0
#: field:ir.model.fields.anonymize.wizard,state:0
msgid "State"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymize.wizard,file_import:0
msgid "Import"
msgstr ""
#. module: anonymization
#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization
msgid "ir.model.fields.anonymization"
msgstr ""
#. module: anonymization
#: model:ir.module.module,shortdesc:anonymization.module_meta_information
msgid "Database anonymization module"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization.history,direction:0
msgid "Direction"
msgstr ""
#. module: anonymization
#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_tree
#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_fields
msgid "Anonymized Fields"
msgstr ""
#. module: anonymization
#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization
msgid "Database anonymization"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,direction:0
msgid "clear -> anonymized"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization,state:0
#: selection:ir.model.fields.anonymize.wizard,state:0
msgid "Anonymized"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization,state:0
msgid "unknown"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization,model_id:0
msgid "Object"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization.history,filepath:0
msgid "File path"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymization.history,date:0
msgid "Date"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymize.wizard,file_export:0
msgid "Export"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymize.wizard:0
msgid "Reverse the Database Anonymization"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymize.wizard:0
msgid "Database Anonymization"
msgstr ""
#. module: anonymization
#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_wizard
msgid "Anonymize database"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymization.history:0
#: field:ir.model.fields.anonymization.history,field_ids:0
msgid "Fields"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization,state:0
#: selection:ir.model.fields.anonymize.wizard,state:0
msgid "Clear"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymize.wizard:0
#: field:ir.model.fields.anonymize.wizard,summary:0
msgid "Summary"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymization:0
msgid "Anonymized Field"
msgstr ""
#. module: anonymization
#: model:ir.module.module,description:anonymization.module_meta_information
msgid ""
"\n"
"This module allows you to anonymize a database.\n"
" "
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymize.wizard,state:0
msgid "Unstable"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,state:0
msgid "Exception occured"
msgstr ""
#. module: anonymization
#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_history_tree
#: view:ir.model.fields.anonymization.history:0
#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_history
msgid "Anonymization History"
msgstr ""
#. module: anonymization
#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization_history
msgid "ir.model.fields.anonymization.history"
msgstr ""
#. module: anonymization
#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymize_wizard
#: view:ir.model.fields.anonymize.wizard:0
msgid "Anonymize Database"
msgstr ""
#. module: anonymization
#: field:ir.model.fields.anonymize.wizard,name:0
msgid "File Name"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,direction:0
msgid "anonymized -> clear"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,state:0
msgid "Started"
msgstr ""
#. module: anonymization
#: selection:ir.model.fields.anonymization.history,state:0
msgid "Done"
msgstr ""
#. module: anonymization
#: view:ir.model.fields.anonymization.history:0
#: field:ir.model.fields.anonymization.history,msg:0
#: field:ir.model.fields.anonymize.wizard,msg:0
msgid "Message"
msgstr ""

View File

@ -0,0 +1,35 @@
id,model_name,field_name
anonymization_field_res_partner_name,res.partner,name
anonymization_field_res_partner_code,res.partner,ref
anonymization_field_res_partner_address_name,res.partner.address,name
anonymization_field_res_partner_address_city,res.partner.address,city
anonymization_field_res_partner_address_street,res.partner.address,street
anonymization_field_res_partner_address_street2,res.partner.address,street2
anonymization_field_res_partner_address_zip,res.partner.address,zip
anonymization_field_res_partner_address_phone,res.partner.address,phone
anonymization_field_res_partner_address_fax,res.partner.address,fax
anonymization_field_res_partner_address_mobile,res.partner.address,mobile
anonymization_field_res_partner_address_email,res.partner.address,email
anonymization_field_account_invoice_amount_untaxed,account.invoice,amount_untaxed
anonymization_field_account_invoice_amount_tax,account.invoice,amount_tax
anonymization_field_account_invoice_amount_total,account.invoice,amount_total
anonymization_field_account_invoice_check_total,account.invoice,check_total
anonymization_field_account_invoice_residual,account.invoice,residual
anonymization_field_account_invoice_line_price_unit,account.invoice.line,price_unit
anonymization_field_account_invoice_line_price_subtotal,account.invoice.line,price_subtotal
anonymization_field_account_move_line_debit,account.move.line,debit
anonymization_field_account_move_line_credit,account.move.line,credit
anonymization_field_account_move_line_tax_amount,account.move.line,tax_amount
anonymization_field_account_move_line_amount_currency,account.move.line,amount_currency
anonymization_field_account_move_line_amount_taxed,account.move.line,amount_taxed
anonymization_field_sale_order_amount_tax,sale.order,amount_tax
anonymization_field_sale_order_amount_total,sale.order,amount_total
anonymization_field_sale_order_amount_untaxed,sale.order,amount_untaxed
anonymization_field_sale_order_line_price_unit,sale.order.line,price_unit
anonymization_field_sale_order_line_discount,sale.order.line,discount
anonymization_field_purchase_order_amount_total,purchase.order,amount_total
anonymization_field_purchase_order_amount_tax,purchase.order,amount_tax
anonymization_field_purchase_order_amount_untaxed,purchase.order,amount_untaxed
anonymization_field_purchase_order_line_price_unit,purchase.order.line,price_unit
anonymization_field_account_invoice_tax_amount,account.invoice.tax,amount
anonymization_field_account_invoice_tax_base,account.invoice.tax,base
1 id model_name field_name
2 anonymization_field_res_partner_name res.partner name
3 anonymization_field_res_partner_code res.partner ref
4 anonymization_field_res_partner_address_name res.partner.address name
5 anonymization_field_res_partner_address_city res.partner.address city
6 anonymization_field_res_partner_address_street res.partner.address street
7 anonymization_field_res_partner_address_street2 res.partner.address street2
8 anonymization_field_res_partner_address_zip res.partner.address zip
9 anonymization_field_res_partner_address_phone res.partner.address phone
10 anonymization_field_res_partner_address_fax res.partner.address fax
11 anonymization_field_res_partner_address_mobile res.partner.address mobile
12 anonymization_field_res_partner_address_email res.partner.address email
13 anonymization_field_account_invoice_amount_untaxed account.invoice amount_untaxed
14 anonymization_field_account_invoice_amount_tax account.invoice amount_tax
15 anonymization_field_account_invoice_amount_total account.invoice amount_total
16 anonymization_field_account_invoice_check_total account.invoice check_total
17 anonymization_field_account_invoice_residual account.invoice residual
18 anonymization_field_account_invoice_line_price_unit account.invoice.line price_unit
19 anonymization_field_account_invoice_line_price_subtotal account.invoice.line price_subtotal
20 anonymization_field_account_move_line_debit account.move.line debit
21 anonymization_field_account_move_line_credit account.move.line credit
22 anonymization_field_account_move_line_tax_amount account.move.line tax_amount
23 anonymization_field_account_move_line_amount_currency account.move.line amount_currency
24 anonymization_field_account_move_line_amount_taxed account.move.line amount_taxed
25 anonymization_field_sale_order_amount_tax sale.order amount_tax
26 anonymization_field_sale_order_amount_total sale.order amount_total
27 anonymization_field_sale_order_amount_untaxed sale.order amount_untaxed
28 anonymization_field_sale_order_line_price_unit sale.order.line price_unit
29 anonymization_field_sale_order_line_discount sale.order.line discount
30 anonymization_field_purchase_order_amount_total purchase.order amount_total
31 anonymization_field_purchase_order_amount_tax purchase.order amount_tax
32 anonymization_field_purchase_order_amount_untaxed purchase.order amount_untaxed
33 anonymization_field_purchase_order_line_price_unit purchase.order.line price_unit
34 anonymization_field_account_invoice_tax_amount account.invoice.tax amount
35 anonymization_field_account_invoice_tax_base account.invoice.tax base

View File

@ -0,0 +1,7 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_ir_model_fields_anonymization_group_system","ir_model_fields_anonymization group_user","model_ir_model_fields_anonymization","base.group_system",1,1,1,1
"access_ir_model_fields_anonymization_user","ir_model_fields_anonymization user","model_ir_model_fields_anonymization",,1,0,0,0
"access_ir_model_fields_anonymization_history_group_system","ir_model_fields_anonymization_history group_user","model_ir_model_fields_anonymization_history","base.group_system",1,1,1,1
"access_ir_model_fields_anonymization_history_user","ir_model_fields_anonymization_history user","model_ir_model_fields_anonymization_history",,1,0,0,0
"access_ir_model_fields_anonymize_wizard_group_system","ir_model_fields_anonymize_wizard group_user","model_ir_model_fields_anonymize_wizard","base.group_system",1,1,1,1
"access_ir_model_fields_anonymize_wizard_user","ir_model_fields_anonymize_wizard user","model_ir_model_fields_anonymize_wizard",,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_ir_model_fields_anonymization_group_system ir_model_fields_anonymization group_user model_ir_model_fields_anonymization base.group_system 1 1 1 1
3 access_ir_model_fields_anonymization_user ir_model_fields_anonymization user model_ir_model_fields_anonymization 1 0 0 0
4 access_ir_model_fields_anonymization_history_group_system ir_model_fields_anonymization_history group_user model_ir_model_fields_anonymization_history base.group_system 1 1 1 1
5 access_ir_model_fields_anonymization_history_user ir_model_fields_anonymization_history user model_ir_model_fields_anonymization_history 1 0 0 0
6 access_ir_model_fields_anonymize_wizard_group_system ir_model_fields_anonymize_wizard group_user model_ir_model_fields_anonymize_wizard base.group_system 1 1 1 1
7 access_ir_model_fields_anonymize_wizard_user ir_model_fields_anonymize_wizard user model_ir_model_fields_anonymize_wizard 1 0 0 0