From 07881a0c50b00635f5becbb7c0c3b416f34e1263 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Fri, 2 Sep 2011 17:18:53 +0530 Subject: [PATCH 01/26] [REF]:execute method in audittrail_objects_proxy bzr revid: nch@tinyerp.com-20110902114853-z7f1uofjgh8poq0z --- addons/audittrail/audittrail.py | 39 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index bfa6bca8f34..ffb44502ba4 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -292,7 +292,7 @@ class audittrail_objects_proxy(object_proxy): def log_fct(self, db, uid, model, method, fct_src, *args): """ - Logging function: This function is performs logging oprations according to method + Logging function: This function is performs logging operations according to method @param db: the current database @param uid: the current user’s ID for security checks, @param object: Object who's values are being changed @@ -482,41 +482,32 @@ class audittrail_objects_proxy(object_proxy): cr = pooler.get_db(db).cursor() cr.autocommit(True) logged_uids = [] + rule = False + ignore_methods = ['default_get','read','fields_view_get','fields_get','search', + 'search_count','name_search','name_get','get','request_get', + 'get_sc', 'unlink', 'write', 'create'] fct_src = super(audittrail_objects_proxy, self).execute - - def my_fct(db, uid, model, method, *args): - rule = False + try: model_ids = model_pool.search(cr, uid, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False - - for model_name in pool.obj_list(): - if model_name == 'audittrail.rule': - rule = True - if not rule: - return fct_src(db, uid_orig, model, method, *args) - if not model_id: - return fct_src(db, uid_orig, model, method, *args) - + if 'audittrail.rule' in pool.obj_list(): + rule = True + if not rule or not model_id: + return fct_src(db, uid_orig, model, method, *args) rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) if not rule_ids: return fct_src(db, uid_orig, model, method, *args) - for thisrule in rule_pool.browse(cr, uid, rule_ids): - for user in thisrule.user_id: - logged_uids.append(user.id) + for model_rule in rule_pool.browse(cr, uid, rule_ids): + logged_uids += map(lambda x:x.id, model_rule.user_id) if not logged_uids or uid in logged_uids: if method in ('read', 'write', 'create', 'unlink'): - if getattr(thisrule, 'log_' + method): + if getattr(model_rule, 'log_' + method): return self.log_fct(db, uid_orig, model, method, fct_src, *args) - - elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create'): - if thisrule.log_action: + elif method not in ignore_methods: + if model_rule.log_action: return self.log_fct(db, uid_orig, model, method, fct_src, *args) - return fct_src(db, uid_orig, model, method, *args) - try: - res = my_fct(db, uid, model, method, *args) - return res finally: cr.close() From 2fef7cd890150c20b4cb9835d601263de1ba5632 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Mon, 5 Sep 2011 14:39:26 +0530 Subject: [PATCH 02/26] [IMP]:refactored with speed improvement:get_value_text method bzr revid: nch@tinyerp.com-20110905090926-jjklwr3p12sbjzl2 --- addons/audittrail/audittrail.py | 50 +++++++++++---------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index ffb44502ba4..0780679f49c 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -203,37 +203,22 @@ class audittrail_objects_proxy(object_proxy): if field_name in('__last_update','id'): return values pool = pooler.get_pool(cr.dbname) - field_pool = pool.get('ir.model.fields') - model_pool = pool.get('ir.model') obj_pool = pool.get(model.model) - if obj_pool._inherits: - inherits_ids = model_pool.search(cr, uid, [('model', '=', obj_pool._inherits.keys()[0])]) - field_ids = field_pool.search(cr, uid, [('name', '=', field_name), ('model_id', 'in', (model.id, inherits_ids[0]))]) - else: - field_ids = field_pool.search(cr, uid, [('name', '=', field_name), ('model_id', '=', model.id)]) - field_id = field_ids and field_ids[0] or False - assert field_id, _("'%s' field does not exist in '%s' model" %(field_name, model.model)) - - field = field_pool.read(cr, uid, field_id) - relation_model = field['relation'] - relation_model_pool = relation_model and pool.get(relation_model) or False - - if field['ttype'] == 'many2one': - res = False - relation_id = False - if values and type(values) == tuple: - relation_id = values[0] - if relation_id and relation_model_pool: - relation_model_object = relation_model_pool.read(cr, uid, relation_id, [relation_model_pool._rec_name]) - res = relation_model_object[relation_model_pool._rec_name] - return res - - elif field['ttype'] in ('many2many','one2many'): - res = [] - for relation_model_object in relation_model_pool.read(cr, uid, values, [relation_model_pool._rec_name]): - res.append(relation_model_object[relation_model_pool._rec_name]) - return res - + field_obj = obj_pool._all_columns.get(field_name, False) + assert field_obj, _("'%s' field does not exist in '%s' model" %(field_name, model.model)) + field_obj = field_obj.column + if field_obj._obj: + relation_model_pool = pool.get(field_obj._obj) + relational_rec_name = relation_model_pool._rec_name + if field_obj._type == 'many2one': + if values and isinstance(values, tuple): + if values[0]: + relation_model_object = relation_model_pool.read(cr, uid, values[0], [relational_rec_name]) + return relation_model_object.get(relational_rec_name) + return False + elif field_obj._type in ('many2many','one2many'): + data = relation_model_pool.read(cr, uid, values, [relational_rec_name]) + return map(lambda x:x.get(relational_rec_name, False), data) return values def create_log_line(self, cr, uid, log_id, model, lines=[]): @@ -482,7 +467,6 @@ class audittrail_objects_proxy(object_proxy): cr = pooler.get_db(db).cursor() cr.autocommit(True) logged_uids = [] - rule = False ignore_methods = ['default_get','read','fields_view_get','fields_get','search', 'search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create'] @@ -490,9 +474,7 @@ class audittrail_objects_proxy(object_proxy): try: model_ids = model_pool.search(cr, uid, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False - if 'audittrail.rule' in pool.obj_list(): - rule = True - if not rule or not model_id: + if not ('audittrail.rule' in pool.obj_list()) or not model_id: return fct_src(db, uid_orig, model, method, *args) rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) if not rule_ids: From 9ebdf040f574d1da0697435fdc4acae864085aec Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Mon, 5 Sep 2011 15:08:41 +0530 Subject: [PATCH 03/26] [IMP]:refactored create_log_line method bzr revid: nch@tinyerp.com-20110905093841-uk7nke7e36gsf4ig --- addons/audittrail/audittrail.py | 39 ++++++++++++++------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 0780679f49c..99382797d72 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -235,43 +235,36 @@ class audittrail_objects_proxy(object_proxy): model_pool = pool.get('ir.model') field_pool = pool.get('ir.model.fields') log_line_pool = pool.get('audittrail.log.line') - #start Loop for line in lines: - if line['name'] in('__last_update','id'): + if line['name'] in ('__last_update','id'): continue + field_obj = obj_pool._all_columns.get(line['name'], False) + assert field_obj, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) + field_obj = field_obj.column + old_value = line.get('old_value', '') + new_value = line.get('new_value', '') + old_value_text = line.get('old_value_text', '') + new_value_text = line.get('new_value_text', '') + search_models = [ model.id ] if obj_pool._inherits: - inherits_ids = model_pool.search(cr, uid, [('model', '=', obj_pool._inherits.keys()[0])]) - field_ids = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', (model.id, inherits_ids[0]))]) - else: - field_ids = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', '=', model.id)]) - field_id = field_ids and field_ids[0] or False - assert field_id, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) - - field = field_pool.read(cr, uid, field_id) - old_value = 'old_value' in line and line['old_value'] or '' - new_value = 'new_value' in line and line['new_value'] or '' - old_value_text = 'old_value_text' in line and line['old_value_text'] or '' - new_value_text = 'new_value_text' in line and line['new_value_text'] or '' - + search_models += model_pool.search(cr, uid, [('model', 'in', obj_pool._inherits.keys())]) + field_id = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', search_models)]) if old_value_text == new_value_text: continue - if field['ttype'] == 'many2one': - if type(old_value) == tuple: - old_value = old_value[0] - if type(new_value) == tuple: - new_value = new_value[0] + if field_obj._type == 'many2one': + old_value = isinstance(old_value, tuple) and old_value[0] or old_value + new_value = isinstance(new_value, tuple) and new_value[0] or new_value vals = { "log_id": log_id, - "field_id": field_id, + "field_id": field_id and field_id[0] or False, "old_value": old_value, "new_value": new_value, "old_value_text": old_value_text, "new_value_text": new_value_text, - "field_description": field['field_description'] + "field_description": field_obj.string } line_id = log_line_pool.create(cr, uid, vals) cr.commit() - #End Loop return True From 2a828b8f5e86ce16bce6a114a34a8f893bed7c6e Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Mon, 5 Sep 2011 17:38:46 +0530 Subject: [PATCH 04/26] [IMP]:refactored log_fct to include create for o2m, m2m method bzr revid: nch@tinyerp.com-20110905120846-sletd1fvcfloqdxy --- addons/audittrail/audittrail.py | 55 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 99382797d72..841eda00d29 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -292,31 +292,38 @@ class audittrail_objects_proxy(object_proxy): model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) model = model_pool.browse(cr, uid, model_id) - + relational_table_log = args and args[-1] == 'child_relation_log' or False if method in ('create'): - res_id = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() - resource = resource_pool.read(cr, uid, res_id, args[0].keys()) - vals = { - "method": method, - "object_id": model.id, - "user_id": uid_orig, - "res_id": resource['id'], - } - if 'id' in resource: - del resource['id'] - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in resource: - line = { - 'name': field, - 'new_value': resource[field], - 'new_value_text': self.get_value_text(cr, uid, field, resource[field], model) - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - - cr.commit() + fields_to_read = [] + if relational_table_log: + res_id = args[0] + else: + res_id = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() + fields_to_read = args[0].keys() + resource = resource_pool.read(cr, uid, res_id, fields_to_read) + if not isinstance(resource, list): + resource = [resource] + vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} + for resource_data in resource: + vals.update({'res_id': resource_data['id']}) + if 'id' in resource_data: + del resource_data['id'] + log_id = log_pool.create(cr, uid, vals) + lines = [] + for field in resource_data: + field_obj = resource_pool._all_columns.get(field, False) + field_obj = field_obj.column + if field_obj._type in ('one2many','many2many'): + self.log_fct(db, uid, field_obj._obj, method, None, resource_data[field], 'child_relation_log') + line = { + 'name': field, + 'new_value': resource_data[field], + 'new_value_text': self.get_value_text(cr, uid, field, resource_data[field], model) + } + lines.append(line) + self.create_log_line(cr, uid, log_id, model, lines) + cr.commit() cr.close() return res_id From 43ff15c84d7f6f674e0201a2674b2a5a4e3c7082 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 11:01:24 +0530 Subject: [PATCH 05/26] [IMP]:get_value_text to use name_get for x2m and simply return [1] arg for m2o tuple bzr revid: nch@tinyerp.com-20110906053124-a3kw3j2g3weln60q --- addons/audittrail/audittrail.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 841eda00d29..1d42000488d 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -204,21 +204,19 @@ class audittrail_objects_proxy(object_proxy): return values pool = pooler.get_pool(cr.dbname) obj_pool = pool.get(model.model) - field_obj = obj_pool._all_columns.get(field_name, False) + field_obj = obj_pool._all_columns.get(field_name) assert field_obj, _("'%s' field does not exist in '%s' model" %(field_name, model.model)) field_obj = field_obj.column if field_obj._obj: relation_model_pool = pool.get(field_obj._obj) relational_rec_name = relation_model_pool._rec_name if field_obj._type == 'many2one': - if values and isinstance(values, tuple): - if values[0]: - relation_model_object = relation_model_pool.read(cr, uid, values[0], [relational_rec_name]) - return relation_model_object.get(relational_rec_name) - return False + if values: + return values[1] + return values elif field_obj._type in ('many2many','one2many'): - data = relation_model_pool.read(cr, uid, values, [relational_rec_name]) - return map(lambda x:x.get(relational_rec_name, False), data) + data = relation_model_pool.name_get(cr, uid, values) + return map(lambda x:x[1], data) return values def create_log_line(self, cr, uid, log_id, model, lines=[]): @@ -312,7 +310,7 @@ class audittrail_objects_proxy(object_proxy): log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource_data: - field_obj = resource_pool._all_columns.get(field, False) + field_obj = resource_pool._all_columns.get(field) field_obj = field_obj.column if field_obj._type in ('one2many','many2many'): self.log_fct(db, uid, field_obj._obj, method, None, resource_data[field], 'child_relation_log') From 1947eed2df667bfd59b7c42306e19ab390170e96 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 11:24:31 +0530 Subject: [PATCH 06/26] [IMP]:support for x2m log unlink bzr revid: nch@tinyerp.com-20110906055431-a87bvbm0o7p1hts5 --- addons/audittrail/audittrail.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 1d42000488d..3f4417a15bb 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -359,33 +359,31 @@ class audittrail_objects_proxy(object_proxy): elif method in ('unlink'): res_ids = args[0] + res = False old_values = {} for res_id in res_ids: old_values[res_id] = resource_pool.read(cr, uid, res_id) - + vals = {'method': method,'object_id': model.id,'user_id': uid_orig} for res_id in res_ids: - vals = { - "method": method, - "object_id": model.id, - "user_id": uid_orig, - "res_id": res_id, - - } + vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: - if field in ('id'): - continue + if field == 'id': continue + field_obj = resource_pool._all_columns.get(field) + field_obj = field_obj.column + if field_obj._type in ('one2many','many2many'): + self.log_fct(db, uid, field_obj._obj, method, None, old_values[res_id][field], 'child_relation_log') line = { 'name': field, 'old_value': old_values[res_id][field], 'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model) } lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + if not relational_table_log: + res = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() cr.close() return res else: From d213821ea0dc2b000f95df025be8f45cefa63330 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 11:52:41 +0530 Subject: [PATCH 07/26] [IMP]:x2m logging when there is any action execute like on_change,copy etc bzr revid: nch@tinyerp.com-20110906062241-373t8wqelc9jsyk9 --- addons/audittrail/audittrail.py | 46 +++++++++++++++------------------ 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 3f4417a15bb..ed4fc5a551d 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -236,7 +236,7 @@ class audittrail_objects_proxy(object_proxy): for line in lines: if line['name'] in ('__last_update','id'): continue - field_obj = obj_pool._all_columns.get(line['name'], False) + field_obj = obj_pool._all_columns.get(line['name']) assert field_obj, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) field_obj = field_obj.column old_value = line.get('old_value', '') @@ -250,8 +250,8 @@ class audittrail_objects_proxy(object_proxy): if old_value_text == new_value_text: continue if field_obj._type == 'many2one': - old_value = isinstance(old_value, tuple) and old_value[0] or old_value - new_value = isinstance(new_value, tuple) and new_value[0] or new_value + old_value = old_value[0] + new_value = new_value[0] vals = { "log_id": log_id, "field_id": field_id and field_id[0] or False, @@ -305,8 +305,7 @@ class audittrail_objects_proxy(object_proxy): vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} for resource_data in resource: vals.update({'res_id': resource_data['id']}) - if 'id' in resource_data: - del resource_data['id'] + del resource_data['id'] log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource_data: @@ -393,38 +392,36 @@ class audittrail_objects_proxy(object_proxy): res_ids = args[0] old_values = {} fields = [] - if len(args)>1 and type(args[1]) == dict: + if len(args) > 1 and isinstance(args[1], dict): fields = args[1].keys() - if type(res_ids) in (long, int): + if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: - for resource in resource_pool.read(cr, uid, res_ids): + resource_data = resource_pool.read(cr, uid, res_ids) + for resource in resource_data: resource_id = resource['id'] - if 'id' in resource: - del resource['id'] + del resource['id'] old_values_text = {} old_value = {} for field in resource.keys(): + field_obj = resource_pool._all_columns.get(field) + field_obj = field_obj.column + if field_obj._type in ('one2many','many2many'): + self.log_fct(db, uid, field_obj._obj, method, None, resource[field], 'child_relation_log') old_value[field] = resource[field] old_values_text[field] = self.get_value_text(cr, uid, field, resource[field], model) old_values[resource_id] = {'text':old_values_text, 'value': old_value} - - res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + if not relational_table_log: + res = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() if res_ids: - for resource in resource_pool.read(cr, uid, res_ids): + resource_data = resource_pool.read(cr, uid, res_ids) + vals = {'method': method,'object_id': model.id,'user_id': uid_orig } + for resource in resource_data: resource_id = resource['id'] - if 'id' in resource: - del resource['id'] - vals = { - "method": method, - "object_id": model.id, - "user_id": uid_orig, - "res_id": resource_id, - } - - + del resource['id'] + vals.update({'res_id': resource_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource.keys(): @@ -436,7 +433,6 @@ class audittrail_objects_proxy(object_proxy): 'old_value_text': old_values[resource_id]['text'][field] } lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) cr.commit() cr.close() From c70d21b6227dac93a0765e80f80a80a3718c532e Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 12:24:16 +0530 Subject: [PATCH 08/26] [IMP]:refactored: removed code duplication bzr revid: nch@tinyerp.com-20110906065416-33abo0zg1e6n55v5 --- addons/audittrail/audittrail.py | 85 +++++++++++---------------------- 1 file changed, 28 insertions(+), 57 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index ed4fc5a551d..4fd99d7bba3 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -250,8 +250,8 @@ class audittrail_objects_proxy(object_proxy): if old_value_text == new_value_text: continue if field_obj._type == 'many2one': - old_value = old_value[0] - new_value = new_value[0] + old_value = old_value and old_value[0] or old_value + new_value = new_value and new_value[0] or new_value vals = { "log_id": log_id, "field_id": field_id and field_id[0] or False, @@ -439,90 +439,61 @@ class audittrail_objects_proxy(object_proxy): return res return True - - - def execute(self, db, uid, model, method, *args, **kw): + def audit_log_call(self, db, uid, model, method, action_type, *args, **argv): """ Overrides Object Proxy execute method @param db: the current database @param uid: the current user's ID for security checks, @param object: Object who's values are being changed @param method: get any method and create log - + @param action_type: either 'execute' or 'workflow' @return: Returns result as per method of Object proxy """ uid_orig = uid uid = 1 pool = pooler.get_pool(db) + logged_uids = [] model_pool = pool.get('ir.model') rule_pool = pool.get('audittrail.rule') cr = pooler.get_db(db).cursor() cr.autocommit(True) - logged_uids = [] - ignore_methods = ['default_get','read','fields_view_get','fields_get','search', - 'search_count','name_search','name_get','get','request_get', - 'get_sc', 'unlink', 'write', 'create'] - fct_src = super(audittrail_objects_proxy, self).execute + if action_type == 'execute': + ignore_methods = ['default_get','read','fields_view_get','fields_get','search', + 'search_count','name_search','name_get','get','request_get', + 'get_sc', 'unlink', 'write', 'create'] + fct_src = super(audittrail_objects_proxy, self).execute + else: + fct_src = super(audittrail_objects_proxy, self).exec_workflow try: model_ids = model_pool.search(cr, uid, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False if not ('audittrail.rule' in pool.obj_list()) or not model_id: - return fct_src(db, uid_orig, model, method, *args) + return fct_src(db, uid_orig, model, method, *args, **argv) rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) if not rule_ids: - return fct_src(db, uid_orig, model, method, *args) - + return fct_src(db, uid_orig, model, method, *args, **argv) for model_rule in rule_pool.browse(cr, uid, rule_ids): logged_uids += map(lambda x:x.id, model_rule.user_id) if not logged_uids or uid in logged_uids: - if method in ('read', 'write', 'create', 'unlink'): - if getattr(model_rule, 'log_' + method): + if action_type == 'execute': + if method in ('read', 'write', 'create', 'unlink'): + if getattr(model_rule, 'log_' + method): + return self.log_fct(db, uid_orig, model, method, fct_src, *args) + elif method not in ignore_methods: + if model_rule.log_action: + return self.log_fct(db, uid_orig, model, method, fct_src, *args) + else: + if model_rule.log_workflow: return self.log_fct(db, uid_orig, model, method, fct_src, *args) - elif method not in ignore_methods: - if model_rule.log_action: - return self.log_fct(db, uid_orig, model, method, fct_src, *args) - return fct_src(db, uid_orig, model, method, *args) + return fct_src(db, uid_orig, model, method, *args, **argv) finally: cr.close() + def execute(self, db, uid, model, method, *args, **argv): + return self.audit_log_call(db, uid, model, method, 'execute', *args, **argv) + def exec_workflow(self, db, uid, model, method, *args, **argv): - uid_orig = uid - uid = 1 - - pool = pooler.get_pool(db) - logged_uids = [] - fct_src = super(audittrail_objects_proxy, self).exec_workflow - field = method - rule = False - model_pool = pool.get('ir.model') - rule_pool = pool.get('audittrail.rule') - cr = pooler.get_db(db).cursor() - cr.autocommit(True) - try: - model_ids = model_pool.search(cr, uid, [('model', '=', model)]) - for obj_name in pool.obj_list(): - if obj_name == 'audittrail.rule': - rule = True - if not rule: - return super(audittrail_objects_proxy, self).exec_workflow(db, uid_orig, model, method, *args, **argv) - if not model_ids: - return super(audittrail_objects_proxy, self).exec_workflow(db, uid_orig, model, method, *args, **argv) - - rule_ids = rule_pool.search(cr, uid, [('object_id', 'in', model_ids), ('state', '=', 'subscribed')]) - if not rule_ids: - return super(audittrail_objects_proxy, self).exec_workflow(db, uid_orig, model, method, *args, **argv) - - for thisrule in rule_pool.browse(cr, uid, rule_ids): - for user in thisrule.user_id: - logged_uids.append(user.id) - if not logged_uids or uid in logged_uids: - if thisrule.log_workflow: - return self.log_fct(db, uid_orig, model, method, fct_src, *args) - return super(audittrail_objects_proxy, self).exec_workflow(db, uid_orig, model, method, *args, **argv) - - return True - finally: - cr.close() + return self.audit_log_call(db, uid, model, method, 'workflow', *args, **argv) audittrail_objects_proxy() From b8596288a8c793c7e1b176d570f291668ab22a1a Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 15:04:53 +0530 Subject: [PATCH 09/26] [IMP]:removedget_value_text to refactore the code..more improvements coming bzr revid: nch@tinyerp.com-20110906093453-c6z7wj8178w6o75g --- addons/audittrail/audittrail.py | 112 +++++++++++++++----------------- 1 file changed, 53 insertions(+), 59 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 4fd99d7bba3..41205982101 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -187,38 +187,6 @@ audittrail_log_line() class audittrail_objects_proxy(object_proxy): """ Uses Object proxy for auditing changes on object of subscribed Rules""" - def get_value_text(self, cr, uid, field_name, values, model, context=None): - """ - Gets textual values for the fields - e.g.: For field of type many2one it gives its name value instead of id - - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param field_name: List of fields for text values - @param values: Values for field to be converted into textual values - @return: values: List of textual values for given fields - """ - if not context: - context = {} - if field_name in('__last_update','id'): - return values - pool = pooler.get_pool(cr.dbname) - obj_pool = pool.get(model.model) - field_obj = obj_pool._all_columns.get(field_name) - assert field_obj, _("'%s' field does not exist in '%s' model" %(field_name, model.model)) - field_obj = field_obj.column - if field_obj._obj: - relation_model_pool = pool.get(field_obj._obj) - relational_rec_name = relation_model_pool._rec_name - if field_obj._type == 'many2one': - if values: - return values[1] - return values - elif field_obj._type in ('many2many','one2many'): - data = relation_model_pool.name_get(cr, uid, values) - return map(lambda x:x[1], data) - return values - def create_log_line(self, cr, uid, log_id, model, lines=[]): """ Creates lines for changed fields with its old and new values @@ -234,8 +202,6 @@ class audittrail_objects_proxy(object_proxy): field_pool = pool.get('ir.model.fields') log_line_pool = pool.get('audittrail.log.line') for line in lines: - if line['name'] in ('__last_update','id'): - continue field_obj = obj_pool._all_columns.get(line['name']) assert field_obj, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) field_obj = field_obj.column @@ -279,7 +245,6 @@ class audittrail_objects_proxy(object_proxy): """ uid_orig = uid uid = 1 - res2 = args pool = pooler.get_pool(db) cr = pooler.get_db(db).cursor() resource_pool = pool.get(model) @@ -303,6 +268,7 @@ class audittrail_objects_proxy(object_proxy): if not isinstance(resource, list): resource = [resource] vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} + new_value_text = '' for resource_data in resource: vals.update({'res_id': resource_data['id']}) del resource_data['id'] @@ -311,12 +277,18 @@ class audittrail_objects_proxy(object_proxy): for field in resource_data: field_obj = resource_pool._all_columns.get(field) field_obj = field_obj.column + new_value_text = resource_data[field] + if field in ('__last_update', 'id'):continue if field_obj._type in ('one2many','many2many'): self.log_fct(db, uid, field_obj._obj, method, None, resource_data[field], 'child_relation_log') + data = pool.get(field_obj._obj).name_get(cr, uid, resource_data[field]) + new_value_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + new_value_text = resource_data[field] and resource_data[field][1] or resource_data[field] line = { 'name': field, 'new_value': resource_data[field], - 'new_value_text': self.get_value_text(cr, uid, field, resource_data[field], model) + 'new_value_text': new_value_text } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -328,29 +300,29 @@ class audittrail_objects_proxy(object_proxy): res_ids = args[0] old_values = {} res = fct_src(db, uid_orig, model.model, method, *args) - if type(res) == list: - for v in res: - old_values[v['id']] = v - else: - old_values[res['id']] = res + map(lambda x:old_values.setdefault(x['id'], x), res) + vals = {'method': method,'object_id': model.id,'user_id': uid_orig} + old_value_text = '' for res_id in old_values: - vals = { - "method": method, - "object_id": model.id, - "user_id": uid_orig, - "res_id": res_id, - - } + vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: + if field in ('__last_update', 'id'):continue + field_obj = resource_pool._all_columns.get(field) + field_obj = field_obj.column + old_value_text = old_values[res_id][field] + if field_obj._type in ('one2many','many2many'): + data = pool.get(field_obj._obj).name_get(cr, uid, old_values[res_id][field]) + old_value_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + old_value_text = old_values[res_id][field] and old_values[res_id][field][1] or old_values[res_id][field] line = { - 'name': field, - 'old_value': old_values[res_id][field], - 'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model) - } + 'name': field, + 'old_value': old_values[res_id][field], + 'old_value_text': old_value_text + } lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) cr.commit() cr.close() @@ -363,20 +335,26 @@ class audittrail_objects_proxy(object_proxy): for res_id in res_ids: old_values[res_id] = resource_pool.read(cr, uid, res_id) vals = {'method': method,'object_id': model.id,'user_id': uid_orig} + old_value_text = '' for res_id in res_ids: vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: - if field == 'id': continue + if field in ('__last_update', 'id'):continue field_obj = resource_pool._all_columns.get(field) field_obj = field_obj.column + old_value_text = old_values[res_id][field] if field_obj._type in ('one2many','many2many'): self.log_fct(db, uid, field_obj._obj, method, None, old_values[res_id][field], 'child_relation_log') + data = pool.get(field_obj._obj).name_get(cr, uid, old_values[res_id][field]) + old_value_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + old_value_text = old_values[res_id][field] and old_values[res_id][field][1] or old_values[res_id][field] line = { 'name': field, 'old_value': old_values[res_id][field], - 'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model) + 'old_value_text': old_value_text } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -398,26 +376,33 @@ class audittrail_objects_proxy(object_proxy): res_ids = [res_ids] if res_ids: resource_data = resource_pool.read(cr, uid, res_ids) + old_text = '' for resource in resource_data: resource_id = resource['id'] del resource['id'] old_values_text = {} old_value = {} for field in resource.keys(): + if field in ('__last_update', 'id'):continue field_obj = resource_pool._all_columns.get(field) field_obj = field_obj.column + old_text = resource[field] if field_obj._type in ('one2many','many2many'): - self.log_fct(db, uid, field_obj._obj, method, None, resource[field], 'child_relation_log') + self.log_fct(db, uid, field_obj._obj, method, None, resource[field], 'child_relation_log') + data = pool.get(field_obj._obj).name_get(cr, uid, resource[field]) + old_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + old_text = resource[field] and resource[field][1] or resource[field] old_value[field] = resource[field] - old_values_text[field] = self.get_value_text(cr, uid, field, resource[field], model) + old_values_text[field] = old_text old_values[resource_id] = {'text':old_values_text, 'value': old_value} if not relational_table_log: res = fct_src(db, uid_orig, model.model, method, *args) cr.commit() - if res_ids: resource_data = resource_pool.read(cr, uid, res_ids) vals = {'method': method,'object_id': model.id,'user_id': uid_orig } + old_value_text = '' for resource in resource_data: resource_id = resource['id'] del resource['id'] @@ -425,11 +410,20 @@ class audittrail_objects_proxy(object_proxy): log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource.keys(): + if field in ('__last_update', 'id'):continue + field_obj = resource_pool._all_columns.get(field) + field_obj = field_obj.column + old_value_text = resource[field] + if field_obj._type in ('one2many','many2many'): + data = pool.get(field_obj._obj).name_get(cr, uid, resource[field]) + old_value_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + old_value_text = resource[field] and resource[field][1] or resource[field] line = { 'name': field, 'new_value': resource[field], 'old_value': old_values[resource_id]['value'][field], - 'new_value_text': self.get_value_text(cr, uid, field, resource[field], model), + 'new_value_text': old_value_text, 'old_value_text': old_values[resource_id]['text'][field] } lines.append(line) From dbd40832d51837844fbf0a94e842c41defbc56dc Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 16:19:49 +0530 Subject: [PATCH 10/26] [REF]:more refactoring bzr revid: nch@tinyerp.com-20110906104949-i6uxzcdden0pq71a --- addons/audittrail/audittrail.py | 75 +++++++++------------------------ 1 file changed, 21 insertions(+), 54 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 41205982101..625d4d46072 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -231,7 +231,17 @@ class audittrail_objects_proxy(object_proxy): cr.commit() return True - + def get_x2m_m2o_values(self, cr, db, uid, pool, resource_pool, method, field, value, recursive=True): + field_obj = (resource_pool._all_columns.get(field)).column + if field_obj._type in ('one2many','many2many'): + if recursive: + self.log_fct(db, uid, field_obj._obj, method, None, value, 'child_relation_log') + data = pool.get(field_obj._obj).name_get(cr, uid, value) + return map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + return value and value[1] or value + return False + def log_fct(self, db, uid, model, method, fct_src, *args): """ Logging function: This function is performs logging operations according to method @@ -268,27 +278,18 @@ class audittrail_objects_proxy(object_proxy): if not isinstance(resource, list): resource = [resource] vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} - new_value_text = '' for resource_data in resource: vals.update({'res_id': resource_data['id']}) del resource_data['id'] log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource_data: - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - new_value_text = resource_data[field] if field in ('__last_update', 'id'):continue - if field_obj._type in ('one2many','many2many'): - self.log_fct(db, uid, field_obj._obj, method, None, resource_data[field], 'child_relation_log') - data = pool.get(field_obj._obj).name_get(cr, uid, resource_data[field]) - new_value_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - new_value_text = resource_data[field] and resource_data[field][1] or resource_data[field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource_data[field]) line = { 'name': field, 'new_value': resource_data[field], - 'new_value_text': new_value_text + 'new_value_text': ret_val and ret_val or resource_data[field] } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -302,25 +303,17 @@ class audittrail_objects_proxy(object_proxy): res = fct_src(db, uid_orig, model.model, method, *args) map(lambda x:old_values.setdefault(x['id'], x), res) vals = {'method': method,'object_id': model.id,'user_id': uid_orig} - old_value_text = '' for res_id in old_values: vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: if field in ('__last_update', 'id'):continue - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - old_value_text = old_values[res_id][field] - if field_obj._type in ('one2many','many2many'): - data = pool.get(field_obj._obj).name_get(cr, uid, old_values[res_id][field]) - old_value_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - old_value_text = old_values[res_id][field] and old_values[res_id][field][1] or old_values[res_id][field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, old_values[res_id][field], False) line = { 'name': field, 'old_value': old_values[res_id][field], - 'old_value_text': old_value_text + 'old_value_text': ret_val and ret_val or old_values[res_id][field] } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -335,26 +328,17 @@ class audittrail_objects_proxy(object_proxy): for res_id in res_ids: old_values[res_id] = resource_pool.read(cr, uid, res_id) vals = {'method': method,'object_id': model.id,'user_id': uid_orig} - old_value_text = '' for res_id in res_ids: vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: if field in ('__last_update', 'id'):continue - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - old_value_text = old_values[res_id][field] - if field_obj._type in ('one2many','many2many'): - self.log_fct(db, uid, field_obj._obj, method, None, old_values[res_id][field], 'child_relation_log') - data = pool.get(field_obj._obj).name_get(cr, uid, old_values[res_id][field]) - old_value_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - old_value_text = old_values[res_id][field] and old_values[res_id][field][1] or old_values[res_id][field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, old_values[res_id][field]) line = { 'name': field, 'old_value': old_values[res_id][field], - 'old_value_text': old_value_text + 'old_value_text': ret_val and ret_val or old_values[res_id][field] } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -376,7 +360,6 @@ class audittrail_objects_proxy(object_proxy): res_ids = [res_ids] if res_ids: resource_data = resource_pool.read(cr, uid, res_ids) - old_text = '' for resource in resource_data: resource_id = resource['id'] del resource['id'] @@ -384,17 +367,9 @@ class audittrail_objects_proxy(object_proxy): old_value = {} for field in resource.keys(): if field in ('__last_update', 'id'):continue - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - old_text = resource[field] - if field_obj._type in ('one2many','many2many'): - self.log_fct(db, uid, field_obj._obj, method, None, resource[field], 'child_relation_log') - data = pool.get(field_obj._obj).name_get(cr, uid, resource[field]) - old_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - old_text = resource[field] and resource[field][1] or resource[field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource[field]) old_value[field] = resource[field] - old_values_text[field] = old_text + old_values_text[field] = ret_val and ret_val or resource[field] old_values[resource_id] = {'text':old_values_text, 'value': old_value} if not relational_table_log: res = fct_src(db, uid_orig, model.model, method, *args) @@ -402,7 +377,6 @@ class audittrail_objects_proxy(object_proxy): if res_ids: resource_data = resource_pool.read(cr, uid, res_ids) vals = {'method': method,'object_id': model.id,'user_id': uid_orig } - old_value_text = '' for resource in resource_data: resource_id = resource['id'] del resource['id'] @@ -411,19 +385,12 @@ class audittrail_objects_proxy(object_proxy): lines = [] for field in resource.keys(): if field in ('__last_update', 'id'):continue - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - old_value_text = resource[field] - if field_obj._type in ('one2many','many2many'): - data = pool.get(field_obj._obj).name_get(cr, uid, resource[field]) - old_value_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - old_value_text = resource[field] and resource[field][1] or resource[field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource[field], False) line = { 'name': field, 'new_value': resource[field], 'old_value': old_values[resource_id]['value'][field], - 'new_value_text': old_value_text, + 'new_value_text': ret_val and ret_val or resource[field], 'old_value_text': old_values[resource_id]['text'][field] } lines.append(line) From 1dce682a32d0d20092553933921056df42a8d145 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 17:57:35 +0530 Subject: [PATCH 11/26] [REF] bzr revid: nch@tinyerp.com-20110906122735-4ikr703mpzbiav5b --- addons/audittrail/audittrail.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 625d4d46072..244f26fba3f 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -266,7 +266,7 @@ class audittrail_objects_proxy(object_proxy): assert model_id, _("'%s' Model does not exist..." %(model)) model = model_pool.browse(cr, uid, model_id) relational_table_log = args and args[-1] == 'child_relation_log' or False - if method in ('create'): + if method == 'create': fields_to_read = [] if relational_table_log: res_id = args[0] @@ -297,7 +297,7 @@ class audittrail_objects_proxy(object_proxy): cr.close() return res_id - elif method in ('read'): + elif method == 'read': res_ids = args[0] old_values = {} res = fct_src(db, uid_orig, model.model, method, *args) @@ -321,7 +321,7 @@ class audittrail_objects_proxy(object_proxy): cr.close() return res - elif method in ('unlink'): + elif method == 'unlink': res_ids = args[0] res = False old_values = {} From 044e4f4c1a6c3be56d8efc581bb4520f6fedf251 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Wed, 7 Sep 2011 18:08:13 +0530 Subject: [PATCH 12/26] [IMP/REF]:allowed entires to be logged when doing different actions/workflow/on_change/write etc...and removed and refactored the code bzr revid: nch@tinyerp.com-20110907123813-4thzx4y3e9vic7uq --- addons/audittrail/audittrail.py | 231 ++++++++++++++++---------------- 1 file changed, 114 insertions(+), 117 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 244f26fba3f..579ba005ba3 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -231,7 +231,7 @@ class audittrail_objects_proxy(object_proxy): cr.commit() return True - def get_x2m_m2o_values(self, cr, db, uid, pool, resource_pool, method, field, value, recursive=True): + def get_value_text(self, cr, db, uid, pool, resource_pool, method, field, value, recursive=True): field_obj = (resource_pool._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): if recursive: @@ -242,6 +242,27 @@ class audittrail_objects_proxy(object_proxy): return value and value[1] or value return False + def start_log_process(self, cr, db, user_id, model, method, resource_data, pool, resource_pool): + key1 = '%s_value'%(method == 'create' and 'new' or 'old') + key2 = '%s_value_text'%(method == 'create' and 'new' or 'old') + uid = 1 + vals = { 'method': method, 'object_id': model.id,'user_id': user_id} + for resource, fields in resource_data.iteritems(): + vals.update({'res_id': resource}) + log_id = pool.get('audittrail.log').create(cr, uid, vals) + lines = [] + for field_key, value in fields.iteritems(): + if field_key in ('__last_update', 'id'):continue + ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field_key, value, method != 'read') + line = { + 'name': field_key, + key1: value, + key2: ret_val and ret_val or value + } + lines.append(line) + self.create_log_line(cr, uid, log_id, model, lines) + return True + def log_fct(self, db, uid, model, method, fct_src, *args): """ Logging function: This function is performs logging operations according to method @@ -259,14 +280,12 @@ class audittrail_objects_proxy(object_proxy): cr = pooler.get_db(db).cursor() resource_pool = pool.get(model) log_pool = pool.get('audittrail.log') - model_pool = pool.get('ir.model') - - model_ids = model_pool.search(cr, uid, [('model', '=', model)]) - model_id = model_ids and model_ids[0] or False - assert model_id, _("'%s' Model does not exist..." %(model)) - model = model_pool.browse(cr, uid, model_id) + model = self.check_rule_subscription(cr, uid, pool, model, False) + assert model, _("'%s' Model does not exist..." %(model)) + relational_table_log = args and args[-1] == 'child_relation_log' or False if method == 'create': + resource_data = {} fields_to_read = [] if relational_table_log: res_id = args[0] @@ -274,77 +293,29 @@ class audittrail_objects_proxy(object_proxy): res_id = fct_src(db, uid_orig, model.model, method, *args) cr.commit() fields_to_read = args[0].keys() - resource = resource_pool.read(cr, uid, res_id, fields_to_read) - if not isinstance(resource, list): - resource = [resource] - vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} - for resource_data in resource: - vals.update({'res_id': resource_data['id']}) - del resource_data['id'] - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in resource_data: - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource_data[field]) - line = { - 'name': field, - 'new_value': resource_data[field], - 'new_value_text': ret_val and ret_val or resource_data[field] - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - cr.commit() + if res_id: + resource = resource_pool.read(cr, uid, res_id, fields_to_read) + if not isinstance(resource,list): + resource = [resource] + map(lambda x: resource_data.setdefault(x['id'], x), resource) + self.start_log_process(cr, db, uid_orig, model, method, resource_data, pool, resource_pool) + cr.commit() cr.close() return res_id - elif method == 'read': + elif method in('read', 'unlink'): res_ids = args[0] old_values = {} - res = fct_src(db, uid_orig, model.model, method, *args) - map(lambda x:old_values.setdefault(x['id'], x), res) - vals = {'method': method,'object_id': model.id,'user_id': uid_orig} - for res_id in old_values: - vals.update({'res_id': res_id}) - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in old_values[res_id]: - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, old_values[res_id][field], False) - line = { - 'name': field, - 'old_value': old_values[res_id][field], - 'old_value_text': ret_val and ret_val or old_values[res_id][field] - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - cr.commit() - cr.close() - return res - - elif method == 'unlink': - res_ids = args[0] - res = False - old_values = {} - for res_id in res_ids: - old_values[res_id] = resource_pool.read(cr, uid, res_id) - vals = {'method': method,'object_id': model.id,'user_id': uid_orig} - for res_id in res_ids: - vals.update({'res_id': res_id}) - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in old_values[res_id]: - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, old_values[res_id][field]) - line = { - 'name': field, - 'old_value': old_values[res_id][field], - 'old_value_text': ret_val and ret_val or old_values[res_id][field] - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - if not relational_table_log: + if method == 'read': res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + map(lambda x: old_values.setdefault(x['id'], x), res) + else: + res = resource_pool.read(cr, uid, res_ids) + map(lambda x:old_values.setdefault(x['id'], x), res) + self.start_log_process(cr, db, uid_orig, model, method, old_values, pool, resource_pool) + if not relational_table_log and method == 'unlink': + res = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() cr.close() return res else: @@ -359,47 +330,79 @@ class audittrail_objects_proxy(object_proxy): if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: - resource_data = resource_pool.read(cr, uid, res_ids) - for resource in resource_data: - resource_id = resource['id'] - del resource['id'] - old_values_text = {} - old_value = {} - for field in resource.keys(): - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource[field]) - old_value[field] = resource[field] - old_values_text[field] = ret_val and ret_val or resource[field] - old_values[resource_id] = {'text':old_values_text, 'value': old_value} - if not relational_table_log: - res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + x2m_old_values = {} + old_values = {} + def inline_process_old_data(res_ids, model, model_id=False): + resource_pool = pool.get(model) + resource_data = resource_pool.read(cr, uid, res_ids) + _old_values = {} + for resource in resource_data: + _old_values_text = {} + _old_value = {} + resource_id = resource['id'] + for field in resource.keys(): + if field in ('__last_update', 'id'):continue + field_obj = (resource_pool._all_columns.get(field)).column + if field_obj._type in ('one2many','many2many'): + x2m_rule_ids, x2m_model = self.check_rule_subscription(cr, uid, pool, field_obj._obj) + if x2m_rule_ids: + x2m_old_values.update(inline_process_old_data(resource[field], field_obj._obj, x2m_model)) + ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field, resource[field], False) + _old_value[field] = resource[field] + _old_values_text[field] = ret_val and ret_val or resource[field] + _old_values[resource_id] = {'text':_old_values_text, 'value': _old_value} + if model_id: + _old_values[resource_id].update({'model_id':model_id}) + return _old_values + old_values.update(inline_process_old_data(res_ids, model.model)) + res = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() if res_ids: - resource_data = resource_pool.read(cr, uid, res_ids) - vals = {'method': method,'object_id': model.id,'user_id': uid_orig } - for resource in resource_data: - resource_id = resource['id'] - del resource['id'] - vals.update({'res_id': resource_id}) - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in resource.keys(): - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource[field], False) - line = { - 'name': field, - 'new_value': resource[field], - 'old_value': old_values[resource_id]['value'][field], - 'new_value_text': ret_val and ret_val or resource[field], - 'old_value_text': old_values[resource_id]['text'][field] - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) + def inline_process_new_data(res_ids, model, dict_to_use={}): + resource_pool = pool.get(model.model) + resource_data = resource_pool.read(cr, uid, res_ids) + vals = {'method': method,'object_id': model.id,'user_id': uid_orig } + for resource in resource_data: + resource_id = resource['id'] + vals.update({'res_id': resource_id}) + log_id = log_pool.create(cr, uid, vals) + lines = [] + for field in resource.keys(): + if field in ('__last_update', 'id'):continue + field_obj = (resource_pool._all_columns.get(field)).column + if field_obj._type in ('one2many','many2many'): + x2m_rule_ids, x2m_model = self.check_rule_subscription(cr, uid, pool, field_obj._obj) + if x2m_rule_ids: + inline_process_new_data(resource[field], x2m_model, x2m_old_values) + ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field, resource[field], False) + line = { + 'name': field, + 'new_value': resource[field], + 'old_value': resource_id in dict_to_use and dict_to_use[resource_id]['value'].get(field), + 'new_value_text': ret_val and ret_val or resource[field], + 'old_value_text': resource_id in dict_to_use and dict_to_use[resource_id]['text'].get(field) + } + lines.append(line) + self.create_log_line(cr, uid, log_id, model, lines) + return True + inline_process_new_data(res_ids, model, old_values) cr.commit() cr.close() return res return True - + + def check_rule_subscription(self, cr, uid, pool, model, rule_check=True): + ''' + Test if the model has been subscribed to the audit rule + if yes then return the rule_ids also return the model browse_record object. + ''' + model_ids = pool.get('ir.model').search(cr, uid, [('model', '=', model)]) + model_obj = model_ids and model_ids[0] and pool.get('ir.model').browse(cr, uid, model_ids[0]) or False + if rule_check: + rule_ids = pool.get('audittrail.rule').search(cr, uid, [('object_id', '=', model_obj.id), ('state', '=', 'subscribed')]) + return rule_ids, model_obj + return model_obj + def audit_log_call(self, db, uid, model, method, action_type, *args, **argv): """ Overrides Object Proxy execute method @@ -414,8 +417,6 @@ class audittrail_objects_proxy(object_proxy): uid = 1 pool = pooler.get_pool(db) logged_uids = [] - model_pool = pool.get('ir.model') - rule_pool = pool.get('audittrail.rule') cr = pooler.get_db(db).cursor() cr.autocommit(True) if action_type == 'execute': @@ -426,14 +427,10 @@ class audittrail_objects_proxy(object_proxy): else: fct_src = super(audittrail_objects_proxy, self).exec_workflow try: - model_ids = model_pool.search(cr, uid, [('model', '=', model)]) - model_id = model_ids and model_ids[0] or False - if not ('audittrail.rule' in pool.obj_list()) or not model_id: + rule_ids, model_obj = self.check_rule_subscription(cr, uid, pool, model) + if not ('audittrail.rule' in pool.obj_list() and model_obj and rule_ids): return fct_src(db, uid_orig, model, method, *args, **argv) - rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) - if not rule_ids: - return fct_src(db, uid_orig, model, method, *args, **argv) - for model_rule in rule_pool.browse(cr, uid, rule_ids): + for model_rule in pool.get('audittrail.rule').browse(cr, uid, rule_ids): logged_uids += map(lambda x:x.id, model_rule.user_id) if not logged_uids or uid in logged_uids: if action_type == 'execute': From 29c44c429210c10c8a40007d5d83c5de9a066523 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Mon, 3 Oct 2011 11:17:33 +0530 Subject: [PATCH 13/26] [IMP]:make compatible to new signatures bzr revid: nch@tinyerp.com-20111003054733-7q2au9vhy01ct5ga --- addons/audittrail/audittrail.py | 160 +++++++++++--------------------- 1 file changed, 56 insertions(+), 104 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 579ba005ba3..cac3ef9b87e 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -43,20 +43,15 @@ class audittrail_rule(osv.osv): "log_create": fields.boolean("Log Creates",help="Select this if you want to keep track of creation on any record of the object of this rule"), "log_action": fields.boolean("Log Action",help="Select this if you want to keep track of actions on the object of this rule"), "log_workflow": fields.boolean("Log Workflow",help="Select this if you want to keep track of workflow on any record of the object of this rule"), - "state": fields.selection((("draft", "Draft"), - ("subscribed", "Subscribed")), - "State", required=True), + "state": fields.selection((("draft", "Draft"), ("subscribed", "Subscribed")), "State", required=True), "action_id": fields.many2one('ir.actions.act_window', "Action ID"), - } - _defaults = { 'state': lambda *a: 'draft', 'log_create': lambda *a: 1, 'log_unlink': lambda *a: 1, 'log_write': lambda *a: 1, } - _sql_constraints = [ ('model_uniq', 'unique (object_id)', """There is a rule defined on this object\n You can not define other on the same!""") ] @@ -123,9 +118,6 @@ class audittrail_rule(osv.osv): #End Loop return True -audittrail_rule() - - class audittrail_log(osv.osv): """ For Audittrail Log @@ -161,9 +153,6 @@ class audittrail_log(osv.osv): } _order = "timestamp desc" -audittrail_log() - - class audittrail_log_line(osv.osv): """ Audittrail Log Line. @@ -181,8 +170,6 @@ class audittrail_log_line(osv.osv): 'field_description': fields.char('Field Description', size=64), } -audittrail_log_line() - class audittrail_objects_proxy(object_proxy): """ Uses Object proxy for auditing changes on object of subscribed Rules""" @@ -228,21 +215,20 @@ class audittrail_objects_proxy(object_proxy): "field_description": field_obj.string } line_id = log_line_pool.create(cr, uid, vals) - cr.commit() return True - def get_value_text(self, cr, db, uid, pool, resource_pool, method, field, value, recursive=True): + def get_value_text(self, cr, uid, pool, resource_pool, method, field, value, recursive=True): field_obj = (resource_pool._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): if recursive: - self.log_fct(db, uid, field_obj._obj, method, None, value, 'child_relation_log') + self.log_fct(cr, uid, field_obj._obj, method, None, value, 'child_relation_log') data = pool.get(field_obj._obj).name_get(cr, uid, value) return map(lambda x:x[1], data) elif field_obj._type == 'many2one': return value and value[1] or value return False - def start_log_process(self, cr, db, user_id, model, method, resource_data, pool, resource_pool): + def start_log_process(self, cr, user_id, model, method, resource_data, pool, resource_pool): key1 = '%s_value'%(method == 'create' and 'new' or 'old') key2 = '%s_value_text'%(method == 'create' and 'new' or 'old') uid = 1 @@ -253,7 +239,7 @@ class audittrail_objects_proxy(object_proxy): lines = [] for field_key, value in fields.iteritems(): if field_key in ('__last_update', 'id'):continue - ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field_key, value, method != 'read') + ret_val = self.get_value_text(cr, uid, pool, resource_pool, method, field_key, value, method != 'read') line = { 'name': field_key, key1: value, @@ -263,7 +249,7 @@ class audittrail_objects_proxy(object_proxy): self.create_log_line(cr, uid, log_id, model, lines) return True - def log_fct(self, db, uid, model, method, fct_src, *args): + def log_fct(self, cr, uid, model, method, fct_src, *args): """ Logging function: This function is performs logging operations according to method @param db: the current database @@ -276,13 +262,14 @@ class audittrail_objects_proxy(object_proxy): """ uid_orig = uid uid = 1 - pool = pooler.get_pool(db) - cr = pooler.get_db(db).cursor() + pool = pooler.get_pool(cr.dbname) resource_pool = pool.get(model) + model_pool = pool.get('ir.model') log_pool = pool.get('audittrail.log') - model = self.check_rule_subscription(cr, uid, pool, model, False) - assert model, _("'%s' Model does not exist..." %(model)) - + model_ids = model_pool.search(cr, 1, [('model', '=', model)]) + model_id = model_ids and model_ids[0] or False + assert model_id, _("'%s' Model does not exist..." %(model)) + model = model_pool.browse(cr, uid, model_id) relational_table_log = args and args[-1] == 'child_relation_log' or False if method == 'create': resource_data = {} @@ -290,33 +277,28 @@ class audittrail_objects_proxy(object_proxy): if relational_table_log: res_id = args[0] else: - res_id = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + res_id = fct_src(cr, uid_orig, model.model, method, *args) fields_to_read = args[0].keys() if res_id: resource = resource_pool.read(cr, uid, res_id, fields_to_read) if not isinstance(resource,list): resource = [resource] map(lambda x: resource_data.setdefault(x['id'], x), resource) - self.start_log_process(cr, db, uid_orig, model, method, resource_data, pool, resource_pool) - cr.commit() - cr.close() + self.start_log_process(cr, uid_orig, model, method, resource_data, pool, resource_pool) return res_id elif method in('read', 'unlink'): res_ids = args[0] old_values = {} if method == 'read': - res = fct_src(db, uid_orig, model.model, method, *args) + res = fct_src(cr, uid_orig, model.model, method, *args) map(lambda x: old_values.setdefault(x['id'], x), res) else: res = resource_pool.read(cr, uid, res_ids) map(lambda x:old_values.setdefault(x['id'], x), res) - self.start_log_process(cr, db, uid_orig, model, method, old_values, pool, resource_pool) + self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) if not relational_table_log and method == 'unlink': - res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() - cr.close() + res = fct_src(cr, uid_orig, model.model, method, *args) return res else: res_ids = [] @@ -344,10 +326,13 @@ class audittrail_objects_proxy(object_proxy): if field in ('__last_update', 'id'):continue field_obj = (resource_pool._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): - x2m_rule_ids, x2m_model = self.check_rule_subscription(cr, uid, pool, field_obj._obj) - if x2m_rule_ids: + if self.check_rules(cr, uid, field_obj._obj, method): + x2m_model_ids = model_pool.search(cr, 1, [('model', '=', field_obj._obj)]) + x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False + assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) + x2m_model = model_pool.browse(cr, uid, x2m_model_id) x2m_old_values.update(inline_process_old_data(resource[field], field_obj._obj, x2m_model)) - ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field, resource[field], False) + ret_val = self.get_value_text(cr, uid, pool, resource_pool, method, field, resource[field], False) _old_value[field] = resource[field] _old_values_text[field] = ret_val and ret_val or resource[field] _old_values[resource_id] = {'text':_old_values_text, 'value': _old_value} @@ -355,8 +340,7 @@ class audittrail_objects_proxy(object_proxy): _old_values[resource_id].update({'model_id':model_id}) return _old_values old_values.update(inline_process_old_data(res_ids, model.model)) - res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + res = fct_src(cr, uid_orig, model.model, method, *args) if res_ids: def inline_process_new_data(res_ids, model, dict_to_use={}): resource_pool = pool.get(model.model) @@ -371,10 +355,14 @@ class audittrail_objects_proxy(object_proxy): if field in ('__last_update', 'id'):continue field_obj = (resource_pool._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): - x2m_rule_ids, x2m_model = self.check_rule_subscription(cr, uid, pool, field_obj._obj) - if x2m_rule_ids: + if self.check_rules(cr, uid, field_obj._obj, method): + x2m_model_ids = model_pool.search(cr, 1, [('model', '=', field_obj._obj)]) + x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False + assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) + x2m_model = model_pool.browse(cr, uid, x2m_model_id) + x2m_old_values.update(inline_process_old_data(resource[field], field_obj._obj, x2m_model)) inline_process_new_data(resource[field], x2m_model, x2m_old_values) - ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field, resource[field], False) + ret_val = self.get_value_text(cr, uid, pool, resource_pool, method, field, resource[field], False) line = { 'name': field, 'new_value': resource[field], @@ -386,72 +374,36 @@ class audittrail_objects_proxy(object_proxy): self.create_log_line(cr, uid, log_id, model, lines) return True inline_process_new_data(res_ids, model, old_values) - cr.commit() - cr.close() return res return True - def check_rule_subscription(self, cr, uid, pool, model, rule_check=True): - ''' - Test if the model has been subscribed to the audit rule - if yes then return the rule_ids also return the model browse_record object. - ''' - model_ids = pool.get('ir.model').search(cr, uid, [('model', '=', model)]) - model_obj = model_ids and model_ids[0] and pool.get('ir.model').browse(cr, uid, model_ids[0]) or False - if rule_check: - rule_ids = pool.get('audittrail.rule').search(cr, uid, [('object_id', '=', model_obj.id), ('state', '=', 'subscribed')]) - return rule_ids, model_obj - return model_obj - - def audit_log_call(self, db, uid, model, method, action_type, *args, **argv): - """ - Overrides Object Proxy execute method - @param db: the current database - @param uid: the current user's ID for security checks, - @param object: Object who's values are being changed - @param method: get any method and create log - @param action_type: either 'execute' or 'workflow' - @return: Returns result as per method of Object proxy - """ - uid_orig = uid - uid = 1 - pool = pooler.get_pool(db) - logged_uids = [] - cr = pooler.get_db(db).cursor() - cr.autocommit(True) - if action_type == 'execute': - ignore_methods = ['default_get','read','fields_view_get','fields_get','search', - 'search_count','name_search','name_get','get','request_get', - 'get_sc', 'unlink', 'write', 'create'] - fct_src = super(audittrail_objects_proxy, self).execute - else: - fct_src = super(audittrail_objects_proxy, self).exec_workflow - try: - rule_ids, model_obj = self.check_rule_subscription(cr, uid, pool, model) - if not ('audittrail.rule' in pool.obj_list() and model_obj and rule_ids): - return fct_src(db, uid_orig, model, method, *args, **argv) - for model_rule in pool.get('audittrail.rule').browse(cr, uid, rule_ids): - logged_uids += map(lambda x:x.id, model_rule.user_id) - if not logged_uids or uid in logged_uids: - if action_type == 'execute': - if method in ('read', 'write', 'create', 'unlink'): - if getattr(model_rule, 'log_' + method): - return self.log_fct(db, uid_orig, model, method, fct_src, *args) - elif method not in ignore_methods: - if model_rule.log_action: - return self.log_fct(db, uid_orig, model, method, fct_src, *args) - else: - if model_rule.log_workflow: - return self.log_fct(db, uid_orig, model, method, fct_src, *args) - return fct_src(db, uid_orig, model, method, *args, **argv) - finally: - cr.close() + def check_rules(self, cr, uid, model, method): + pool = pooler.get_pool(cr.dbname) + # Check if auditrails is installed for that db and then if one rule match + if 'audittrail.rule' in pool.models: + model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', model)]) + model_id = model_ids and model_ids[0] or False + if model_id: + rule_ids = pool.get('audittrail.rule').search(cr, 1, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) + for rule in pool.get('audittrail.rule').read(cr, 1, rule_ids, ['user_id','log_read','log_write','log_create','log_unlink','log_action','log_workflow']): + if len(rule['user_id'])==0 or uid in rule['user_id']: + if rule.get('log_'+method,0): + return True + elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create'): + if rule['log_action']: + return True - def execute(self, db, uid, model, method, *args, **argv): - return self.audit_log_call(db, uid, model, method, 'execute', *args, **argv) + def execute_cr(self, cr, uid, model, method, *args, **kw): + fct_src = super(audittrail_objects_proxy, self).execute_cr + if self.check_rules(cr,uid,model,method): + return self.log_fct(cr, uid, model, method, fct_src, *args) + return fct_src(cr, uid, model, method, *args) - def exec_workflow(self, db, uid, model, method, *args, **argv): - return self.audit_log_call(db, uid, model, method, 'workflow', *args, **argv) + def exec_workflow_cr(self, cr, uid, model, method, *args, **argv): + fct_src = super(audittrail_objects_proxy, self).exec_workflow_cr + if self.check_rules(cr,uid,model,'workflow'): + return self.log_fct(cr, uid, model, method, fct_src, *args) + return fct_src(cr, uid, model, method, *args) audittrail_objects_proxy() From 080e3bfe0ce7fe8127a7d7883e59595acaec78a9 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Mon, 3 Oct 2011 11:40:22 +0530 Subject: [PATCH 14/26] [FIX]:O2M log bug bzr revid: nch@tinyerp.com-20111003061022-nknshc6j591qozmp --- addons/audittrail/audittrail.py | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index cac3ef9b87e..a4fedd206e4 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -360,7 +360,6 @@ class audittrail_objects_proxy(object_proxy): x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = model_pool.browse(cr, uid, x2m_model_id) - x2m_old_values.update(inline_process_old_data(resource[field], field_obj._obj, x2m_model)) inline_process_new_data(resource[field], x2m_model, x2m_old_values) ret_val = self.get_value_text(cr, uid, pool, resource_pool, method, field, resource[field], False) line = { From 87b823056fade5df1376ad2fc2426b10e325cc6e Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Wed, 9 Nov 2011 11:39:30 +0530 Subject: [PATCH 15/26] [FIX]:remove log_id which does not have any lines to log bzr revid: nch@tinyerp.com-20111109060930-ti0gx3sed7a12329 --- addons/audittrail/audittrail.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 79277bdf0d5..49a9850a3dd 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -206,6 +206,7 @@ class audittrail_objects_proxy(object_proxy): model_pool = pool.get('ir.model') field_pool = pool.get('ir.model.fields') log_line_pool = pool.get('audittrail.log.line') + line_id = False for line in lines: field_obj = obj_pool._all_columns.get(line['name']) assert field_obj, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) @@ -233,6 +234,8 @@ class audittrail_objects_proxy(object_proxy): "field_description": field_obj.string } line_id = log_line_pool.create(cr, uid, vals) + if not line_id: + pool.get('audittrail.log').unlink(cr, uid, log_id) return True def start_log_process(self, cr, user_id, model, method, resource_data, pool, resource_pool): From c452e5ae0da2c409f540b730b4d581ea51492274 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Wed, 9 Nov 2011 15:57:29 +0530 Subject: [PATCH 16/26] [IMP]:previous fix bzr revid: nch@tinyerp.com-20111109102729-a6c1ru7byniz9ggu --- addons/audittrail/audittrail.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 49a9850a3dd..b82d22f5450 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -206,21 +206,16 @@ class audittrail_objects_proxy(object_proxy): model_pool = pool.get('ir.model') field_pool = pool.get('ir.model.fields') log_line_pool = pool.get('audittrail.log.line') - line_id = False for line in lines: field_obj = obj_pool._all_columns.get(line['name']) assert field_obj, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) field_obj = field_obj.column old_value = line.get('old_value', '') new_value = line.get('new_value', '') - old_value_text = line.get('old_value_text', '') - new_value_text = line.get('new_value_text', '') search_models = [model.id] if obj_pool._inherits: search_models += model_pool.search(cr, uid, [('model', 'in', obj_pool._inherits.keys())]) field_id = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', search_models)]) - if old_value_text == new_value_text: - continue if field_obj._type == 'many2one': old_value = old_value and old_value[0] or old_value new_value = new_value and new_value[0] or new_value @@ -229,13 +224,11 @@ class audittrail_objects_proxy(object_proxy): "field_id": field_id and field_id[0] or False, "old_value": old_value, "new_value": new_value, - "old_value_text": old_value_text, - "new_value_text": new_value_text, + "old_value_text": line.get('old_value_text', ''), + "new_value_text": line.get('new_value_text', ''), "field_description": field_obj.string } line_id = log_line_pool.create(cr, uid, vals) - if not line_id: - pool.get('audittrail.log').unlink(cr, uid, log_id) return True def start_log_process(self, cr, user_id, model, method, resource_data, pool, resource_pool): @@ -358,7 +351,8 @@ class audittrail_objects_proxy(object_proxy): for resource in resource_data: resource_id = resource['id'] vals.update({'res_id': resource_id}) - log_id = log_pool.create(cr, uid, vals) + if resource_id not in dict_to_use: + vals.update({'method': 'create'}) lines = [] for field in resource.keys(): if field in ('__last_update', 'id'):continue @@ -378,8 +372,11 @@ class audittrail_objects_proxy(object_proxy): 'new_value_text': ret_val and ret_val or resource[field], 'old_value_text': resource_id in dict_to_use and dict_to_use[resource_id]['text'].get(field) } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) + if line.get('new_value_text') != line.get('old_value_text'): + lines.append(line) + if lines: + log_id = log_pool.create(cr, uid, vals) + self.create_log_line(cr, uid, log_id, model, lines) return True inline_process_new_data(res_ids, model, old_values) return res From eb36286eea84432f21393512e1ce60e792ab889c Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Wed, 16 Nov 2011 12:10:50 +0530 Subject: [PATCH 17/26] [IMP]:added Doc string bzr revid: nch@tinyerp.com-20111116064050-cve3d7pcx8pdrsv0 --- addons/audittrail/audittrail.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index b82d22f5450..3d7bf8587f7 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -179,7 +179,16 @@ class audittrail_objects_proxy(object_proxy): If the field is a many2one, it returns the name. If it's a one2many or a many2many, it returns a list of name. In other cases, it just returns the value. + @param cr: the current row, from the database cursor, + @param uid: the current user’s ID for security checks, + @param pool: current db's pooler object. + @param resource_pool: pooler object of the model who's values are being changed. + @param field: for which the text value is to be returned. + @param value: value of the field. + @param recursive: True or False, True will repeat the process recursively + @return: string value or a list of values(for O2M/M2M) """ + field_obj = (resource_pool._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): if recursive: @@ -232,6 +241,18 @@ class audittrail_objects_proxy(object_proxy): return True def start_log_process(self, cr, user_id, model, method, resource_data, pool, resource_pool): + """ + Logging function: This function performs the logging operation for create/read/unlink operation + :@param cr: the current row, from the database cursor, + :@param user_id: the current user’s ID, + :param model: Object which values are being changed + :param method: method to log: create, read, unlink + :param resource_data: list of data modified for the model + :@param pool: current db's pooler object. + :@param resource_pool: pooler object of the model who's values are being changed. + :return:True + + """ key1 = '%s_value'%(method == 'create' and 'new' or 'old') key2 = '%s_value_text'%(method == 'create' and 'new' or 'old') uid = 1 From f2c68745f0d3fbdcbf93eb2b39da2f61d35bb717 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Thu, 17 Nov 2011 12:39:05 +0530 Subject: [PATCH 18/26] [FIX/IMP/REF]:1::fix copy,unlink,workflow actions,refactored the way data was processed and logged for the actions and workflow actions. bzr revid: nch@tinyerp.com-20111117070905-14b23ir45vx7rg7x --- addons/audittrail/audittrail.py | 118 ++++++++++++++------------------ 1 file changed, 52 insertions(+), 66 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 3d7bf8587f7..60a5aa4f9be 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -194,7 +194,7 @@ class audittrail_objects_proxy(object_proxy): if recursive: self.log_fct(cr, uid, field_obj._obj, method, None, value, 'child_relation_log') data = pool.get(field_obj._obj).name_get(cr, uid, value) - #return the modifications on *2many fields as a list of names + #return the modifications on x2many fields as a list of names return map(lambda x:x[1], data) elif field_obj._type == 'many2one': #return the modifications on a many2one field as the name of the value @@ -287,7 +287,6 @@ class audittrail_objects_proxy(object_proxy): pool = pooler.get_pool(cr.dbname) resource_pool = pool.get(model) model_pool = pool.get('ir.model') - log_pool = pool.get('audittrail.log') model_ids = model_pool.search(cr, 1, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) @@ -335,74 +334,61 @@ class audittrail_objects_proxy(object_proxy): if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: - x2m_old_values = {} - old_values = {} - def inline_process_old_data(res_ids, model, model_id=False): - resource_pool = pool.get(model) - resource_data = resource_pool.read(cr, uid, res_ids) - _old_values = {} - for resource in resource_data: - _old_values_text = {} - _old_value = {} - resource_id = resource['id'] - for field in resource.keys(): - if field in ('__last_update', 'id'):continue - field_obj = (resource_pool._all_columns.get(field)).column - if field_obj._type in ('one2many','many2many'): - if self.check_rules(cr, uid, field_obj._obj, method): - x2m_model_ids = model_pool.search(cr, 1, [('model', '=', field_obj._obj)]) - x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False - assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) - x2m_model = model_pool.browse(cr, uid, x2m_model_id) - x2m_old_values.update(inline_process_old_data(resource[field], field_obj._obj, x2m_model)) - ret_val = self.get_value_text(cr, uid, pool, resource_pool, method, field, resource[field], False) - _old_value[field] = resource[field] - _old_values_text[field] = ret_val and ret_val or resource[field] - _old_values[resource_id] = {'text':_old_values_text, 'value': _old_value} - if model_id: - _old_values[resource_id].update({'model_id':model_id}) - return _old_values - old_values.update(inline_process_old_data(res_ids, model.model)) + old_values = self.process_data(cr, uid_orig, pool, res_ids, model, method, type='old') res = fct_src(cr, uid_orig, model.model, method, *args) + if method == 'copy': + res_ids = [res] if res_ids: - def inline_process_new_data(res_ids, model, dict_to_use={}): - resource_pool = pool.get(model.model) - resource_data = resource_pool.read(cr, uid, res_ids) - vals = {'method': method,'object_id': model.id,'user_id': uid_orig } - for resource in resource_data: - resource_id = resource['id'] - vals.update({'res_id': resource_id}) - if resource_id not in dict_to_use: - vals.update({'method': 'create'}) - lines = [] - for field in resource.keys(): - if field in ('__last_update', 'id'):continue - field_obj = (resource_pool._all_columns.get(field)).column - if field_obj._type in ('one2many','many2many'): - if self.check_rules(cr, uid, field_obj._obj, method): - x2m_model_ids = model_pool.search(cr, 1, [('model', '=', field_obj._obj)]) - x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False - assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) - x2m_model = model_pool.browse(cr, uid, x2m_model_id) - inline_process_new_data(resource[field], x2m_model, x2m_old_values) - ret_val = self.get_value_text(cr, uid, pool, resource_pool, method, field, resource[field], False) - line = { - 'name': field, - 'new_value': resource[field], - 'old_value': resource_id in dict_to_use and dict_to_use[resource_id]['value'].get(field), - 'new_value_text': ret_val and ret_val or resource[field], - 'old_value_text': resource_id in dict_to_use and dict_to_use[resource_id]['text'].get(field) - } - if line.get('new_value_text') != line.get('old_value_text'): - lines.append(line) - if lines: - log_id = log_pool.create(cr, uid, vals) - self.create_log_line(cr, uid, log_id, model, lines) - return True - inline_process_new_data(res_ids, model, old_values) + self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values) return res return True - + + def process_data(self, cr, uid_orig, pool, res_ids, model, method, original_values={}, type='new'): + resource_pool = pool.get(model.model) + resource_data = resource_pool.read(cr, 1, res_ids) + _old_values = {} + for resource in resource_data: + _old_values_text = {} + _old_value = {} + resource_id = resource['id'] + if type == 'new': + vals = {'method': method,'object_id': model.id,'user_id': uid_orig } + vals.update({'res_id': resource_id}) + if resource_id not in original_values and method !='copy': + vals.update({'method': 'create'}) + lines = [] + for field in resource: + if field in ('__last_update', 'id'):continue + field_obj = (resource_pool._all_columns.get(field)).column + if field_obj._type in ('one2many','many2many'): + if self.check_rules(cr, 1, field_obj._obj, method): + x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)]) + x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False + assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) + x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) + _old_values[field] = self.process_data(cr, 1, pool, resource[field], x2m_model, method, original_values.get(field,{}), type=type) + ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) + if type == 'new': + line = { + 'name': field, + 'new_value': resource[field], + 'old_value': resource_id in original_values and original_values[resource_id]['value'].get(field), + 'new_value_text': ret_val and ret_val or resource[field], + 'old_value_text': resource_id in original_values and original_values[resource_id]['text'].get(field) + } + if line.get('new_value_text') != line.get('old_value_text'): + lines.append(line) + else: + _old_value[field] = resource[field] + _old_values_text[field] = ret_val and ret_val or resource[field] + if type == 'new': + if lines: + log_id = pool.get('audittrail.log').create(cr, 1, vals) + self.create_log_line(cr, 1, log_id, model, lines) + else: + _old_values[resource_id] = {'text':_old_values_text, 'value': _old_value} + return _old_values + def check_rules(self, cr, uid, model, method): pool = pooler.get_pool(cr.dbname) # Check if auditrails is installed for that db and then if one rule match From 98f060b12861fda6f29e9a0b9d94a11d767d5fe4 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Thu, 17 Nov 2011 12:55:18 +0530 Subject: [PATCH 19/26] [IMP]:added doc string for missing methods bzr revid: nch@tinyerp.com-20111117072518-iohc292j52qke927 --- addons/audittrail/audittrail.py | 54 ++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 60a5aa4f9be..9c7ea06fad5 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -207,7 +207,7 @@ class audittrail_objects_proxy(object_proxy): @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, - @param model: Object who's values are being changed + @param model: Object whose values are being changed @param lines: List of values for line is to be created """ pool = pooler.get_pool(cr.dbname) @@ -243,14 +243,14 @@ class audittrail_objects_proxy(object_proxy): def start_log_process(self, cr, user_id, model, method, resource_data, pool, resource_pool): """ Logging function: This function performs the logging operation for create/read/unlink operation - :@param cr: the current row, from the database cursor, - :@param user_id: the current user’s ID, - :param model: Object which values are being changed - :param method: method to log: create, read, unlink - :param resource_data: list of data modified for the model - :@param pool: current db's pooler object. - :@param resource_pool: pooler object of the model who's values are being changed. - :return:True + @param cr: the current row, from the database cursor, + @param user_id: the current user’s ID, + param model: Object whose values are being changed + param method: method to log: create, read, unlink + param resource_data: list of data modified for the model + @param pool: current db's pooler object. + @param resource_pool: pooler object of the model who's values are being changed. + return:True """ key1 = '%s_value'%(method == 'create' and 'new' or 'old') @@ -276,11 +276,11 @@ class audittrail_objects_proxy(object_proxy): def log_fct(self, cr, uid, model, method, fct_src, *args): """ Logging function: This function is performing the logging operation - :param model: Object which values are being changed - :param method: method to log: create, read, write, unlink - :param fct_src: execute method of Object proxy + @param model: Object whose values are being changed + @param method: method to log: create, read, write, unlink + @param fct_src: execute method of Object proxy - :return: Returns result as per method of Object proxy + @return: Returns result as per method of Object proxy """ uid_orig = uid uid = 1 @@ -344,6 +344,22 @@ class audittrail_objects_proxy(object_proxy): return True def process_data(self, cr, uid_orig, pool, res_ids, model, method, original_values={}, type='new'): + """ + This is specially created to log actions and workflow actions on an object recursively + processes and iterates recursively old data (i.e before the method was executed ) + and stores it in a dict then this dict is used to compare with the new data + (i.e after the method execution) and log the changes. + + @param cr: the current row, from the database cursor, + @param uid_orig: the current user’s ID, + @param pool: current db's pooler object. + @param res_ids: Id's of resource to be logged/compared. + @param model: Object whose values are being changed + @param method: method to log: create, read, unlink,write,actions,workflow actions + @param original_values: dict of values of res_ids read before execution of the method only when type is 'new' + @param type: Either of 'new' or 'old' to know which data to process. + @return: dict of values + """ resource_pool = pool.get(model.model) resource_data = resource_pool.read(cr, 1, res_ids) _old_values = {} @@ -390,15 +406,23 @@ class audittrail_objects_proxy(object_proxy): return _old_values def check_rules(self, cr, uid, model, method): + """ + Checks if auditrails is installed for that db and then if one rule match + @param cr: the current row, from the database cursor, + @param uid: the current user’s ID, + @param model: Object whose values are being changed + @param method: method to log: create, read, unlink,write,actions,workflow actions + @return: True or False + """ + pool = pooler.get_pool(cr.dbname) - # Check if auditrails is installed for that db and then if one rule match if 'audittrail.rule' in pool.models: model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False if model_id: rule_ids = pool.get('audittrail.rule').search(cr, 1, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) for rule in pool.get('audittrail.rule').read(cr, 1, rule_ids, ['user_id','log_read','log_write','log_create','log_unlink','log_action','log_workflow']): - if len(rule['user_id'])==0 or uid in rule['user_id']: + if len(rule['user_id']) == 0 or uid in rule['user_id']: if rule.get('log_'+method,0): return True elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create'): From 9589ee8d348dab8d76dd1837695ce7a90005912d Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Thu, 17 Nov 2011 14:14:38 +0530 Subject: [PATCH 20/26] [FIX]:fix useless creat of log record for 'x2M' in read operation bzr revid: nch@tinyerp.com-20111117084438-fx63kcqx3my59sxa --- addons/audittrail/audittrail.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 9c7ea06fad5..47a0122b035 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -258,8 +258,6 @@ class audittrail_objects_proxy(object_proxy): uid = 1 vals = { 'method': method, 'object_id': model.id,'user_id': user_id} for resource, fields in resource_data.iteritems(): - vals.update({'res_id': resource}) - log_id = pool.get('audittrail.log').create(cr, uid, vals) lines = [] for field_key, value in fields.iteritems(): if field_key in ('__last_update', 'id'):continue @@ -270,7 +268,10 @@ class audittrail_objects_proxy(object_proxy): key2: ret_val and ret_val or value } lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) + if lines: + vals.update({'res_id': resource}) + log_id = pool.get('audittrail.log').create(cr, uid, vals) + self.create_log_line(cr, uid, log_id, model, lines) return True def log_fct(self, cr, uid, model, method, fct_src, *args): From d28d46e26fdb5374185a5956ff5bbf43a658e82b Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Fri, 18 Nov 2011 21:27:13 +0100 Subject: [PATCH 21/26] [REF] audittrail: code refactoring. still not totally working x_x bzr revid: qdp-launchpad@openerp.com-20111118202713-e5f1mtzx3gyovdok --- addons/audittrail/audittrail.py | 213 ++++++++++++++++++++++++++------ 1 file changed, 172 insertions(+), 41 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 454f925c0f5..6946511045e 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -245,33 +245,35 @@ class audittrail_objects_proxy(object_proxy): Logging function: This function performs the logging operation for create/read/unlink operation :param cr: the current row, from the database cursor, :param user_id: the current user’s ID, - :param model: Object whose values are being changed + :param model: record of ir.model related to the object which values are being changed :param method: method to log: create, read, unlink :param resource_data: list of data modified for the model :param pool: current db's pooler object. :param resource_pool: pooler object of the model who's values are being changed. :return:True """ - key1 = '%s_value'%(method == 'create' and 'new' or 'old') - key2 = '%s_value_text'%(method == 'create' and 'new' or 'old') - vals = { 'method': method, 'object_id': model.id,'user_id': user_id} - for resource, fields in resource_data.iteritems(): - lines = [] - for field_key, value in fields.iteritems(): - if field_key in ('__last_update', 'id'):continue - ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field_key, value, method != 'read') - line = { - 'name': field_key, - key1: value, - key2: ret_val and ret_val or value - } - lines.append(line) - if lines: - vals.update({'res_id': resource}) - log_id = pool.get('audittrail.log').create(cr, 1, vals) - self.create_log_line(cr, uid, log_id, model, lines) + #checking if an audittrail rule apply in super admin mode + if self.check_rules(cr, 1, model.model, method): + key1 = '%s_value'%(method == 'create' and 'new' or 'old') + key2 = '%s_value_text'%(method == 'create' and 'new' or 'old') + vals = {'method': method, 'object_id': model.id,'user_id': user_id} + for resource, fields in resource_data.iteritems(): + lines = [] + for field_key, value in fields.iteritems(): + if field_key in ('__last_update', 'id'):continue + ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field_key, value, method != 'read') + line = { + 'name': field_key, + key1: value, + key2: ret_val and ret_val or value + } + lines.append(line) + if lines: + vals.update({'res_id': resource}) + log_id = pool.get('audittrail.log').create(cr, 1, vals) + self.create_log_line(cr, 1, log_id, model, lines) return True - + def log_fct(self, cr, uid, model, method, fct_src, *args): """ Logging function: This function is performing the logging operation @@ -292,21 +294,23 @@ class audittrail_objects_proxy(object_proxy): model = model_pool.browse(cr, uid, model_id) relational_table_log = True if (args and args[-1] == 'child_relation_log') else False + print model.model + print method + print ">>>>>>>" if method == 'create': resource_data = {} fields_to_read = [] if relational_table_log: - res_id = args[0] + res = args[0] else: - res_id = fct_src(cr, uid_orig, model.model, method, *args) + res = fct_src(cr, uid_orig, model.model, method, *args) fields_to_read = args[0].keys() - if res_id: - resource = resource_pool.read(cr, uid, res_id, fields_to_read) + if res: + resource = resource_pool.read(cr, uid, res, fields_to_read) if not isinstance(resource,list): resource = [resource] map(lambda x: resource_data.setdefault(x['id'], x), resource) self.start_log_process(cr, uid_orig, model, method, resource_data, pool, resource_pool) - return res_id elif method in('read', 'unlink'): res_ids = args[0] @@ -320,7 +324,6 @@ class audittrail_objects_proxy(object_proxy): self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) if not relational_table_log and method == 'unlink': res = fct_src(cr, uid_orig, model.model, method, *args) - return res else: #method is write or workflow action res_ids = [] res = True @@ -334,18 +337,142 @@ class audittrail_objects_proxy(object_proxy): res_ids = [res_ids] if res_ids: #store the old values into a dictionary - old_values = self.process_data(cr, uid_orig, pool, res_ids, model, method, type='old') + old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) #process the original function or workflow trigger res = fct_src(cr, uid_orig, model.model, method, *args) if method == 'copy': res_ids = [res] if res_ids: - #check the new value and log the changes if any - self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values) - return res + #check the new value and store them into a dictionary + new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) + self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values) + return res + + def get_data(self, cr, uid_orig, pool, res_ids, model, method): + """ + This is specially created to log actions and workflow actions on an object recursively. + It processes and iterates recursively on old data (i.e before the method was executed ) + and stores it in a dict. Then this dict is used to compare with the new data + (i.e after the method execution) and log the changes. + + :param cr: the current row, from the database cursor, + :param uid_orig: the current user’s ID, + :param pool: current db's pooler object. + :param res_ids: Id's of resource to be logged/compared. + :param model: Object whose values are being changed + :param method: method to log: create, read, unlink,write,actions,workflow actions + :return: dict mapping a tuple (model_id, resource_id) with its value and textual value + { (model_id, resource_id): { 'value': ... + 'textual_value': ... + }, + } + """ + data = {} + # read all the field of the given resource in super admin mode + resource_pool = pool.get(model.model) + for resource in resource_pool.read(cr, 1, res_ids): + values_text = {} + values = {} + resource_id = resource['id'] + for field in resource: + if field in ('__last_update', 'id'): + continue + values[field] = resource[field] + ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) + values_text[field] = ret_val and ret_val or resource[field] + data[(model.id, resource_id)] = {'text':values_text, 'value': values} + field_obj = resource_pool._all_columns.get(field).column + if field_obj._type in ('one2many','many2many'): + #checking if an audittrail rule apply in super admin mode + if self.check_rules(cr, 1, field_obj._obj, method): + #checking if the model associated to a *2m field exists, in super admin mode + x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)]) + x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False + assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) + x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) + data.update(self.get_data(cr, 1, pool, resource[field], x2m_model, method)) + return data + + def prepare_audittrail_log_line(self, cr, uid, pool, model, resource, method, old_values, new_values): + lines = { + (model.id, resource['id']): [] + } + for field in resource: + if field in ('__last_update', 'id'): + continue + field_obj = (pool.get(model.model)._all_columns.get(field)).column + if field_obj._type in ('one2many','many2many'): + #checking if an audittrail rule apply in super admin mode + if self.check_rules(cr, 1, field_obj._obj, method): + #checking if the model associated to a *2m field exists, in super admin mode + x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)]) + x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False + assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) + x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) + if resource[field]: + for resource_id in resource[field]: + x2many_new_values = new_values[(x2m_model_id, resource_id)] + x2many_new_values.update({'id': resource['id']}) + x = self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, x2many_new_values, method, old_values.get((x2m_model_id, resource_id),{}), x2many_new_values) + lines.update(x) + # if the value value is different than the old value: record the change + if old_values[(model.id, resource['id'])]['value'][field] != new_values[(model.id, resource['id'])]['value'][field]: + data = { + 'name': field, + 'new_value': resource[field], + 'old_value': (model.id, resource['id']) in old_values and old_values[(model.id, resource['id'])]['value'].get(field), + 'new_value_text': (model.id, resource['id']) in new_values and new_values[(model.id, resource['id'])]['text'].get(field), + 'old_value_text': (model.id, resource['id']) in old_values and old_values[(model.id, resource['id'])]['text'].get(field) + } + lines[(model.id, resource['id'])].append(data) + return lines + + def process_data(self, cr, uid, pool, res_ids, model, method, old_values={}, new_values={}): + """ + This is specially created to log actions and workflow actions on an object recursively. + It processes and iterates recursively on old data (i.e before the method was executed ) + and stores it in a dict. Then this dict is used to compare with the new data + (i.e after the method execution) and log the changes. + + :param cr: the current row, from the database cursor, + :param uid: the current user’s ID, + :param pool: current db's pooler object. + :param res_ids: Id's of resource to be logged/compared. + :param model: Object whose values are being changed + :param method: method to log: create, read, unlink,write,actions,workflow actions + :param original_values: dict of values of res_ids read before execution of the method only when type is 'new' + :param type: Either of 'new' or 'old' to know which data to process. + :return: dict of values + """ + # read all the field of the given resource in super admin mode + for resource in pool.get(model.model).read(cr, 1, res_ids): + lines = self.prepare_audittrail_log_line(cr, uid, pool, model, resource, method, old_values, new_values) + + # if at least one modification has been found + for model_id, resource_id in lines: + vals = { + 'method': method, + 'object_id': model_id, + 'user_id': uid, + 'res_id': resource_id, + } + if (model_id, resource_id) not in old_values and method !='copy': + # the resource was not existing so we are forcing the method to 'create' + # (because it could also come with the value 'write' if we are creating + # new record through a one2many field) + vals.update({'method': 'create'}) + if (model_id, resource_id) not in new_values and method !='copy': + # the resource is not existing anymore so we are forcing the method to 'unlink' + # (because it could also come with the value 'write' if we are deleting the + # record through a one2many field) + vals.update({'method': 'unlink'}) + # create the audittrail log in super admin mode + log_id = pool.get('audittrail.log').create(cr, 1, vals) + model = pool.get('ir.model').browse(cr, uid, model_id) + self.create_log_line(cr, 1, log_id, model, lines[(model_id, resource_id)]) return True - def process_data(self, cr, uid_orig, pool, res_ids, model, method, original_values={}, type='new'): + def process_data_old(self, cr, uid_orig, pool, res_ids, model, method, original_values={}, type='new'): """ This is specially created to log actions and workflow actions on an object recursively. It processes and iterates recursively on old data (i.e before the method was executed ) @@ -369,15 +496,7 @@ class audittrail_objects_proxy(object_proxy): _old_values_text = {} _old_value = {} resource_id = resource['id'] - if type == 'new': - vals = {'method': method,'object_id': model.id,'user_id': uid_orig } - vals.update({'res_id': resource_id}) - if resource_id not in original_values and method !='copy': - # the resource was not existing so we are forcing the method to 'create' - # (because it could also come with the value 'write' if we are creating - # new record through a one2many field) - vals.update({'method': 'create'}) - lines = [] + lines = [] for field in resource: if field in ('__last_update', 'id'):continue field_obj = (resource_pool._all_columns.get(field)).column @@ -406,6 +525,18 @@ class audittrail_objects_proxy(object_proxy): _old_values_text[field] = ret_val and ret_val or resource[field] if type == 'new': if lines: + vals = { + 'method': method, + 'object_id': model.id, + 'user_id': uid_orig, + 'res_id': resource_id, + } + if resource_id not in original_values and method !='copy': + # the resource was not existing so we are forcing the method to 'create' + # (because it could also come with the value 'write' if we are creating + # new record through a one2many field) + vals.update({'method': 'create'}) + # create the audittrail log in super admin mode log_id = pool.get('audittrail.log').create(cr, 1, vals) self.create_log_line(cr, 1, log_id, model, lines) else: @@ -417,7 +548,7 @@ class audittrail_objects_proxy(object_proxy): Checks if auditrails is installed for that db and then if one rule match @param cr: the current row, from the database cursor, @param uid: the current user’s ID, - @param model: Object whose values are being changed + @param model: value of _name of the object which values are being changed @param method: method to log: create, read, unlink,write,actions,workflow actions @return: True or False """ From 6a2403444183de1f64a9d61d67c38a25d58743fd Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 14:33:20 +0100 Subject: [PATCH 22/26] [REF] audittrail: refactoring of audittrail module bzr revid: qdp-launchpad@openerp.com-20111121133320-plb409qv2l7valqk --- addons/audittrail/audittrail.py | 89 +++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 6946511045e..8007d348749 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -294,9 +294,6 @@ class audittrail_objects_proxy(object_proxy): model = model_pool.browse(cr, uid, model_id) relational_table_log = True if (args and args[-1] == 'child_relation_log') else False - print model.model - print method - print ">>>>>>>" if method == 'create': resource_data = {} fields_to_read = [] @@ -368,7 +365,7 @@ class audittrail_objects_proxy(object_proxy): } """ data = {} - # read all the field of the given resource in super admin mode + # read all the fields of the given resource in super admin mode resource_pool = pool.get(model.model) for resource in resource_pool.read(cr, 1, res_ids): values_text = {} @@ -394,58 +391,87 @@ class audittrail_objects_proxy(object_proxy): return data def prepare_audittrail_log_line(self, cr, uid, pool, model, resource, method, old_values, new_values): + """ + This function compares the old data (i.e before the method was executed) and the new data + (after the method was executed) and returns a structure with all the needed information to + log those differences. + + :param cr: the current row, from the database cursor, + :param uid: the current user’s ID, + :param pool: current db's pooler object. + :param model: model object which values are being changed + :param resource: dictionary mapping all the fields of a given resource and its current values + :param method: method to log: create, read, unlink, write, actions, workflow actions + :param old_values: dict of values read before execution of the method + :param new_values: dict of values read after execution of the method + + :return: dictionary with + * keys: tuples build as ID of model object to log and ID of resource to log + * values: list of all the changes in field values for this couple (model, resource) + return { + (model.id, resource['id']): [] + } + + The reason why the structure returned is build as above is because when modifying an existing + record (res.partner, for example), we may have to log a change done in a x2many field (on + res.partner.address, for example) + """ + key = (model.id, resource['id']) lines = { - (model.id, resource['id']): [] + key: [] } for field in resource: if field in ('__last_update', 'id'): continue field_obj = (pool.get(model.model)._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): - #checking if an audittrail rule apply in super admin mode + # checking if an audittrail rule apply in super admin mode if self.check_rules(cr, 1, field_obj._obj, method): - #checking if the model associated to a *2m field exists, in super admin mode + # checking if the model associated to a *2m field exists, in super admin mode x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)]) x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) - if resource[field]: - for resource_id in resource[field]: - x2many_new_values = new_values[(x2m_model_id, resource_id)] - x2many_new_values.update({'id': resource['id']}) - x = self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, x2many_new_values, method, old_values.get((x2m_model_id, resource_id),{}), x2many_new_values) - lines.update(x) + resource_ids = list(set(old_values[(model.id, resource['id'])]['value'][field] + new_values[(model.id, resource['id'])]['value'][field])) + if resource_ids: + for resource_id in resource_ids: + if (x2m_model_id, resource_id) in new_values: + x2many_values = new_values[(x2m_model_id, resource_id)] + else: + x2many_values = old_values[(x2m_model_id, resource_id)] + x2many_values['value'].update({'id': resource_id}) + lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, x2many_values['value'], method, old_values, new_values)) # if the value value is different than the old value: record the change - if old_values[(model.id, resource['id'])]['value'][field] != new_values[(model.id, resource['id'])]['value'][field]: + if key not in old_values or key not in new_values or old_values[key]['value'][field] != new_values[key]['value'][field]: data = { 'name': field, 'new_value': resource[field], - 'old_value': (model.id, resource['id']) in old_values and old_values[(model.id, resource['id'])]['value'].get(field), - 'new_value_text': (model.id, resource['id']) in new_values and new_values[(model.id, resource['id'])]['text'].get(field), - 'old_value_text': (model.id, resource['id']) in old_values and old_values[(model.id, resource['id'])]['text'].get(field) + 'old_value': key in old_values and old_values[key]['value'].get(field), + 'new_value_text': key in new_values and new_values[key]['text'].get(field), + 'old_value_text': key in old_values and old_values[key]['text'].get(field) } - lines[(model.id, resource['id'])].append(data) + lines[key].append(data) return lines def process_data(self, cr, uid, pool, res_ids, model, method, old_values={}, new_values={}): """ - This is specially created to log actions and workflow actions on an object recursively. - It processes and iterates recursively on old data (i.e before the method was executed ) - and stores it in a dict. Then this dict is used to compare with the new data - (i.e after the method execution) and log the changes. + This function processes and iterates recursively to log the difference between the old + data (i.e before the method was executed) and the new data and creates audittrail log + accordingly. :param cr: the current row, from the database cursor, :param uid: the current user’s ID, :param pool: current db's pooler object. :param res_ids: Id's of resource to be logged/compared. - :param model: Object whose values are being changed - :param method: method to log: create, read, unlink,write,actions,workflow actions - :param original_values: dict of values of res_ids read before execution of the method only when type is 'new' - :param type: Either of 'new' or 'old' to know which data to process. - :return: dict of values + :param model: model object which values are being changed + :param method: method to log: create, read, unlink, write, actions, workflow actions + :param old_values: dict of values read before execution of the method + :param new_values: dict of values read after execution of the method + :return: True """ # read all the field of the given resource in super admin mode for resource in pool.get(model.model).read(cr, 1, res_ids): + # compare old and new values and get audittrail log lines accordingly lines = self.prepare_audittrail_log_line(cr, uid, pool, model, resource, method, old_values, new_values) # if at least one modification has been found @@ -466,10 +492,11 @@ class audittrail_objects_proxy(object_proxy): # (because it could also come with the value 'write' if we are deleting the # record through a one2many field) vals.update({'method': 'unlink'}) - # create the audittrail log in super admin mode - log_id = pool.get('audittrail.log').create(cr, 1, vals) - model = pool.get('ir.model').browse(cr, uid, model_id) - self.create_log_line(cr, 1, log_id, model, lines[(model_id, resource_id)]) + # create the audittrail log in super admin mode, only if a change has been detected + if lines[(model_id, resource_id)]: + log_id = pool.get('audittrail.log').create(cr, 1, vals) + model = pool.get('ir.model').browse(cr, uid, model_id) + self.create_log_line(cr, 1, log_id, model, lines[(model_id, resource_id)]) return True def process_data_old(self, cr, uid_orig, pool, res_ids, model, method, original_values={}, type='new'): From f25889155b77348c92f7eb77f54ecccfa24ac677 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 15:34:50 +0100 Subject: [PATCH 23/26] [REF] audittrail: refactoring of audittrail module. (Finished the write/actions, wkf actions) bzr revid: qdp-launchpad@openerp.com-20111121143450-yzkuk0rpomy2aync --- addons/audittrail/audittrail.py | 206 ++++++++++---------------------- 1 file changed, 65 insertions(+), 141 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 8007d348749..1baf767fcac 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -175,9 +175,9 @@ class audittrail_objects_proxy(object_proxy): def get_value_text(self, cr, uid, pool, resource_pool, method, field, value, recursive=True): """ - Gets textual values for the fields. - If the field is a many2one, it returns the name. - If it's a one2many or a many2many, it returns a list of name. + Gets textual values for the fields. + If the field is a many2one, it returns the name. + If it's a one2many or a many2many, it returns a list of name. In other cases, it just returns the value. :param cr: the current row, from the database cursor, :param uid: the current user’s ID for security checks, @@ -185,7 +185,7 @@ class audittrail_objects_proxy(object_proxy): :param resource_pool: pooler object of the model which values are being changed. :param field: for which the text value is to be returned. :param value: value of the field. - :param recursive: True or False, True will repeat the process recursively => when? + :param recursive: True or False, True will repeat the process recursively :return: string value or a list of values(for O2M/M2M) """ @@ -195,11 +195,13 @@ class audittrail_objects_proxy(object_proxy): self.log_fct(cr, uid, field_obj._obj, method, None, value, 'child_relation_log') data = pool.get(field_obj._obj).name_get(cr, uid, value) #return the modifications on x2many fields as a list of names - return map(lambda x:x[1], data) + res = map(lambda x:x[1], data) elif field_obj._type == 'many2one': #return the modifications on a many2one field as its value returned by name_get() - return value and value[1] or value - return value + res = value and value[1] or value + else: + res = value + return res def create_log_line(self, cr, uid, log_id, model, lines=[]): """ @@ -274,7 +276,7 @@ class audittrail_objects_proxy(object_proxy): self.create_log_line(cr, 1, log_id, model, lines) return True - def log_fct(self, cr, uid, model, method, fct_src, *args): + def log_fct(self, cr, uid_orig, model, method, fct_src, *args): """ Logging function: This function is performing the logging operation @param model: Object whose values are being changed @@ -283,15 +285,13 @@ class audittrail_objects_proxy(object_proxy): @return: Returns result as per method of Object proxy """ - uid_orig = uid - uid = 1 pool = pooler.get_pool(cr.dbname) resource_pool = pool.get(model) model_pool = pool.get('ir.model') model_ids = model_pool.search(cr, 1, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) - model = model_pool.browse(cr, uid, model_id) + model = model_pool.browse(cr, 1, model_id) relational_table_log = True if (args and args[-1] == 'child_relation_log') else False if method == 'create': @@ -303,61 +303,57 @@ class audittrail_objects_proxy(object_proxy): res = fct_src(cr, uid_orig, model.model, method, *args) fields_to_read = args[0].keys() if res: - resource = resource_pool.read(cr, uid, res, fields_to_read) + resource = resource_pool.read(cr, 1, res, fields_to_read) if not isinstance(resource,list): resource = [resource] map(lambda x: resource_data.setdefault(x['id'], x), resource) self.start_log_process(cr, uid_orig, model, method, resource_data, pool, resource_pool) - - elif method in('read', 'unlink'): + elif method == 'read': + old_values = {} + res = fct_src(cr, uid_orig, model.model, method, *args) + map(lambda x: old_values.setdefault(x['id'], x), res) + self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) + elif method == 'unlink': res_ids = args[0] old_values = {} - if method == 'read': - res = fct_src(cr, uid_orig, model.model, method, *args) - map(lambda x: old_values.setdefault(x['id'], x), res) - else: - res = resource_pool.read(cr, uid, res_ids) - map(lambda x:old_values.setdefault(x['id'], x), res) + res = resource_pool.read(cr, 1, res_ids) + map(lambda x:old_values.setdefault(x['id'], x), res) self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) - if not relational_table_log and method == 'unlink': + if not relational_table_log: res = fct_src(cr, uid_orig, model.model, method, *args) - else: #method is write or workflow action + else: #method is write, action or workflow action res_ids = [] - res = True if args: res_ids = args[0] - old_values = {} - fields = [] - if len(args) > 1 and isinstance(args[1], dict): - fields = args[1].keys() if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: #store the old values into a dictionary old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) - #process the original function or workflow trigger + #process the original function, workflow trigger... res = fct_src(cr, uid_orig, model.model, method, *args) if method == 'copy': res_ids = [res] if res_ids: - #check the new value and store them into a dictionary + #check the new values and store them into a dictionary new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) + #compare the old and new values and create audittrail log if needed self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values) return res - def get_data(self, cr, uid_orig, pool, res_ids, model, method): + def get_data(self, cr, uid, pool, res_ids, model, method): """ - This is specially created to log actions and workflow actions on an object recursively. - It processes and iterates recursively on old data (i.e before the method was executed ) - and stores it in a dict. Then this dict is used to compare with the new data - (i.e after the method execution) and log the changes. + This function simply read all the fields of the given res_ids, and also recurisvely on + all records of a x2m fields read that need to be logged. Then it returns the result in + convenient structure that will be used as comparison basis. :param cr: the current row, from the database cursor, - :param uid_orig: the current user’s ID, + :param uid: the current user’s ID. This parameter is currently not used as every + operation to get data is made as super admin. Though, it could be usefull later. :param pool: current db's pooler object. :param res_ids: Id's of resource to be logged/compared. :param model: Object whose values are being changed - :param method: method to log: create, read, unlink,write,actions,workflow actions + :param method: method to log: create, read, unlink, write, actions, workflow actions :return: dict mapping a tuple (model_id, resource_id) with its value and textual value { (model_id, resource_id): { 'value': ... 'textual_value': ... @@ -365,42 +361,46 @@ class audittrail_objects_proxy(object_proxy): } """ data = {} - # read all the fields of the given resource in super admin mode resource_pool = pool.get(model.model) + # read all the fields of the given resources in super admin mode for resource in resource_pool.read(cr, 1, res_ids): - values_text = {} values = {} + values_text = {} resource_id = resource['id'] + # loop on each field on the res_ids we just have read for field in resource: if field in ('__last_update', 'id'): continue values[field] = resource[field] - ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) - values_text[field] = ret_val and ret_val or resource[field] - data[(model.id, resource_id)] = {'text':values_text, 'value': values} + # get the textual value of that field for this record + values_text[field] = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) + field_obj = resource_pool._all_columns.get(field).column if field_obj._type in ('one2many','many2many'): - #checking if an audittrail rule apply in super admin mode + # check if an audittrail rule apply in super admin mode if self.check_rules(cr, 1, field_obj._obj, method): - #checking if the model associated to a *2m field exists, in super admin mode + # check if the model associated to a *2m field exists, in super admin mode x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)]) x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) + #recursive call on x2m fields that need to be checked too data.update(self.get_data(cr, 1, pool, resource[field], x2m_model, method)) + data[(model.id, resource_id)] = {'text':values_text, 'value': values} return data - def prepare_audittrail_log_line(self, cr, uid, pool, model, resource, method, old_values, new_values): + def prepare_audittrail_log_line(self, cr, uid, pool, model, resource_id, method, old_values, new_values): """ This function compares the old data (i.e before the method was executed) and the new data (after the method was executed) and returns a structure with all the needed information to log those differences. :param cr: the current row, from the database cursor, - :param uid: the current user’s ID, + :param uid: the current user’s ID. This parameter is currently not used as every + operation to get data is made as super admin. Though, it could be usefull later. :param pool: current db's pooler object. :param model: model object which values are being changed - :param resource: dictionary mapping all the fields of a given resource and its current values + :param resource_id: ID of record to which values are being changed :param method: method to log: create, read, unlink, write, actions, workflow actions :param old_values: dict of values read before execution of the method :param new_values: dict of values read after execution of the method @@ -409,21 +409,20 @@ class audittrail_objects_proxy(object_proxy): * keys: tuples build as ID of model object to log and ID of resource to log * values: list of all the changes in field values for this couple (model, resource) return { - (model.id, resource['id']): [] + (model.id, resource_id): [] } The reason why the structure returned is build as above is because when modifying an existing record (res.partner, for example), we may have to log a change done in a x2many field (on res.partner.address, for example) """ - key = (model.id, resource['id']) + key = (model.id, resource_id) lines = { key: [] } - for field in resource: - if field in ('__last_update', 'id'): - continue - field_obj = (pool.get(model.model)._all_columns.get(field)).column + # loop on all the fields + for field_name, field_definition in pool.get(model.model)._all_columns.items(): + field_obj = field_definition.column if field_obj._type in ('one2many','many2many'): # checking if an audittrail rule apply in super admin mode if self.check_rules(cr, 1, field_obj._obj, method): @@ -432,23 +431,19 @@ class audittrail_objects_proxy(object_proxy): x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) - resource_ids = list(set(old_values[(model.id, resource['id'])]['value'][field] + new_values[(model.id, resource['id'])]['value'][field])) - if resource_ids: - for resource_id in resource_ids: - if (x2m_model_id, resource_id) in new_values: - x2many_values = new_values[(x2m_model_id, resource_id)] - else: - x2many_values = old_values[(x2m_model_id, resource_id)] - x2many_values['value'].update({'id': resource_id}) - lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, x2many_values['value'], method, old_values, new_values)) + # the resource_ids that need to be checked are the sum of both old and previous values (because we + # need to log also creation or deletion in those list). We use list(set(...)) to remove duplicates. + res_ids = list(set(old_values[key]['value'][field_name] + new_values[key]['value'][field_name])) + for res_id in res_ids: + lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, res_id, method, old_values, new_values)) # if the value value is different than the old value: record the change - if key not in old_values or key not in new_values or old_values[key]['value'][field] != new_values[key]['value'][field]: + if key not in old_values or key not in new_values or old_values[key]['value'][field_name] != new_values[key]['value'][field_name]: data = { - 'name': field, - 'new_value': resource[field], - 'old_value': key in old_values and old_values[key]['value'].get(field), - 'new_value_text': key in new_values and new_values[key]['text'].get(field), - 'old_value_text': key in old_values and old_values[key]['text'].get(field) + 'name': field_name, + 'new_value': key in new_values and new_values[key]['value'].get(field_name), + 'old_value': key in old_values and old_values[key]['value'].get(field_name), + 'new_value_text': key in new_values and new_values[key]['text'].get(field_name), + 'old_value_text': key in old_values and old_values[key]['text'].get(field_name) } lines[key].append(data) return lines @@ -469,10 +464,10 @@ class audittrail_objects_proxy(object_proxy): :param new_values: dict of values read after execution of the method :return: True """ - # read all the field of the given resource in super admin mode - for resource in pool.get(model.model).read(cr, 1, res_ids): + # loop on all the given ids + for res_id in res_ids: # compare old and new values and get audittrail log lines accordingly - lines = self.prepare_audittrail_log_line(cr, uid, pool, model, resource, method, old_values, new_values) + lines = self.prepare_audittrail_log_line(cr, uid, pool, model, res_id, method, old_values, new_values) # if at least one modification has been found for model_id, resource_id in lines: @@ -499,77 +494,6 @@ class audittrail_objects_proxy(object_proxy): self.create_log_line(cr, 1, log_id, model, lines[(model_id, resource_id)]) return True - def process_data_old(self, cr, uid_orig, pool, res_ids, model, method, original_values={}, type='new'): - """ - This is specially created to log actions and workflow actions on an object recursively. - It processes and iterates recursively on old data (i.e before the method was executed ) - and stores it in a dict. Then this dict is used to compare with the new data - (i.e after the method execution) and log the changes. - - :param cr: the current row, from the database cursor, - :param uid_orig: the current user’s ID, - :param pool: current db's pooler object. - :param res_ids: Id's of resource to be logged/compared. - :param model: Object whose values are being changed - :param method: method to log: create, read, unlink,write,actions,workflow actions - :param original_values: dict of values of res_ids read before execution of the method only when type is 'new' - :param type: Either of 'new' or 'old' to know which data to process. - :return: dict of values - """ - resource_pool = pool.get(model.model) - resource_data = resource_pool.read(cr, 1, res_ids) - _old_values = {} - for resource in resource_data: - _old_values_text = {} - _old_value = {} - resource_id = resource['id'] - lines = [] - for field in resource: - if field in ('__last_update', 'id'):continue - field_obj = (resource_pool._all_columns.get(field)).column - if field_obj._type in ('one2many','many2many'): - #checking if an audittrail rule apply in super admin mode - if self.check_rules(cr, 1, field_obj._obj, method): - #checking if the model associated to a *2m field exists, in super admin mode - x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)]) - x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False - assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) - x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) - _old_values[field] = self.process_data(cr, 1, pool, resource[field], x2m_model, method, original_values.get(field,{}), type=type) - ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) - if type == 'new': - line = { - 'name': field, - 'new_value': resource[field], - 'old_value': resource_id in original_values and original_values[resource_id]['value'].get(field), - 'new_value_text': ret_val and ret_val or resource[field], - 'old_value_text': resource_id in original_values and original_values[resource_id]['text'].get(field) - } - if line.get('new_value_text') != line.get('old_value_text'): - lines.append(line) - else: - _old_value[field] = resource[field] - _old_values_text[field] = ret_val and ret_val or resource[field] - if type == 'new': - if lines: - vals = { - 'method': method, - 'object_id': model.id, - 'user_id': uid_orig, - 'res_id': resource_id, - } - if resource_id not in original_values and method !='copy': - # the resource was not existing so we are forcing the method to 'create' - # (because it could also come with the value 'write' if we are creating - # new record through a one2many field) - vals.update({'method': 'create'}) - # create the audittrail log in super admin mode - log_id = pool.get('audittrail.log').create(cr, 1, vals) - self.create_log_line(cr, 1, log_id, model, lines) - else: - _old_values[resource_id] = {'text':_old_values_text, 'value': _old_value} - return _old_values - def check_rules(self, cr, uid, model, method): """ Checks if auditrails is installed for that db and then if one rule match From b2c3de062a638a6add58a3da74ace18470a5430c Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 17:10:51 +0100 Subject: [PATCH 24/26] [REF] audittrail: refactoring of audittrail module. (read, unlink and create) bzr revid: qdp-launchpad@openerp.com-20111121161051-rskfs0gfkh3e73d7 --- addons/audittrail/audittrail.py | 111 ++++++++++++-------------------- 1 file changed, 40 insertions(+), 71 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 1baf767fcac..d26d43f00e5 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -173,7 +173,7 @@ class audittrail_log_line(osv.osv): class audittrail_objects_proxy(object_proxy): """ Uses Object proxy for auditing changes on object of subscribed Rules""" - def get_value_text(self, cr, uid, pool, resource_pool, method, field, value, recursive=True): + def get_value_text(self, cr, uid, pool, resource_pool, method, field, value): """ Gets textual values for the fields. If the field is a many2one, it returns the name. @@ -191,8 +191,6 @@ class audittrail_objects_proxy(object_proxy): field_obj = (resource_pool._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): - if recursive: - self.log_fct(cr, uid, field_obj._obj, method, None, value, 'child_relation_log') data = pool.get(field_obj._obj).name_get(cr, uid, value) #return the modifications on x2many fields as a list of names res = map(lambda x:x[1], data) @@ -242,40 +240,6 @@ class audittrail_objects_proxy(object_proxy): line_id = log_line_pool.create(cr, uid, vals) return True - def start_log_process(self, cr, user_id, model, method, resource_data, pool, resource_pool): - """ - Logging function: This function performs the logging operation for create/read/unlink operation - :param cr: the current row, from the database cursor, - :param user_id: the current user’s ID, - :param model: record of ir.model related to the object which values are being changed - :param method: method to log: create, read, unlink - :param resource_data: list of data modified for the model - :param pool: current db's pooler object. - :param resource_pool: pooler object of the model who's values are being changed. - :return:True - """ - #checking if an audittrail rule apply in super admin mode - if self.check_rules(cr, 1, model.model, method): - key1 = '%s_value'%(method == 'create' and 'new' or 'old') - key2 = '%s_value_text'%(method == 'create' and 'new' or 'old') - vals = {'method': method, 'object_id': model.id,'user_id': user_id} - for resource, fields in resource_data.iteritems(): - lines = [] - for field_key, value in fields.iteritems(): - if field_key in ('__last_update', 'id'):continue - ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field_key, value, method != 'read') - line = { - 'name': field_key, - key1: value, - key2: ret_val and ret_val or value - } - lines.append(line) - if lines: - vals.update({'res_id': resource}) - log_id = pool.get('audittrail.log').create(cr, 1, vals) - self.create_log_line(cr, 1, log_id, model, lines) - return True - def log_fct(self, cr, uid_orig, model, method, fct_src, *args): """ Logging function: This function is performing the logging operation @@ -292,35 +256,28 @@ class audittrail_objects_proxy(object_proxy): model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) model = model_pool.browse(cr, 1, model_id) - relational_table_log = True if (args and args[-1] == 'child_relation_log') else False + field_list = [] if method == 'create': - resource_data = {} - fields_to_read = [] - if relational_table_log: - res = args[0] - else: - res = fct_src(cr, uid_orig, model.model, method, *args) - fields_to_read = args[0].keys() - if res: - resource = resource_pool.read(cr, 1, res, fields_to_read) - if not isinstance(resource,list): - resource = [resource] - map(lambda x: resource_data.setdefault(x['id'], x), resource) - self.start_log_process(cr, uid_orig, model, method, resource_data, pool, resource_pool) - elif method == 'read': old_values = {} res = fct_src(cr, uid_orig, model.model, method, *args) - map(lambda x: old_values.setdefault(x['id'], x), res) - self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) + if res: + res_ids = [res] + new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) + elif method == 'read': + new_values = {} + old_values = {} + res = fct_src(cr, uid_orig, model.model, method, *args) + field_list = args[1] + res_ids = [] + for record in res: + res_ids.append(record['id']) + old_values[(model.id, record['id'])] = {'value': record, 'text': record} elif method == 'unlink': res_ids = args[0] - old_values = {} - res = resource_pool.read(cr, 1, res_ids) - map(lambda x:old_values.setdefault(x['id'], x), res) - self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) - if not relational_table_log: - res = fct_src(cr, uid_orig, model.model, method, *args) + old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) + res = fct_src(cr, uid_orig, model.model, method, *args) + new_values = {} else: #method is write, action or workflow action res_ids = [] if args: @@ -337,8 +294,8 @@ class audittrail_objects_proxy(object_proxy): if res_ids: #check the new values and store them into a dictionary new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) - #compare the old and new values and create audittrail log if needed - self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values) + #compare the old and new values and create audittrail log if needed + self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values, field_list) return res def get_data(self, cr, uid, pool, res_ids, model, method): @@ -389,7 +346,7 @@ class audittrail_objects_proxy(object_proxy): data[(model.id, resource_id)] = {'text':values_text, 'value': values} return data - def prepare_audittrail_log_line(self, cr, uid, pool, model, resource_id, method, old_values, new_values): + def prepare_audittrail_log_line(self, cr, uid, pool, model, resource_id, method, old_values, new_values, field_list=[]): """ This function compares the old data (i.e before the method was executed) and the new data (after the method was executed) and returns a structure with all the needed information to @@ -404,8 +361,11 @@ class audittrail_objects_proxy(object_proxy): :param method: method to log: create, read, unlink, write, actions, workflow actions :param old_values: dict of values read before execution of the method :param new_values: dict of values read after execution of the method + :param field_list: optional argument containing the list of fields to log. Currently only + used when performing a read, it could be usefull later on if we want to log the write + on specific fields only. - :return: dictionary with + :return: dictionary with * keys: tuples build as ID of model object to log and ID of resource to log * values: list of all the changes in field values for this couple (model, resource) return { @@ -422,6 +382,9 @@ class audittrail_objects_proxy(object_proxy): } # loop on all the fields for field_name, field_definition in pool.get(model.model)._all_columns.items(): + #if the field_list param is given, skip all the fields not in that list + if field_list and field_name not in field_list: + continue field_obj = field_definition.column if field_obj._type in ('one2many','many2many'): # checking if an audittrail rule apply in super admin mode @@ -432,10 +395,13 @@ class audittrail_objects_proxy(object_proxy): assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) # the resource_ids that need to be checked are the sum of both old and previous values (because we - # need to log also creation or deletion in those list). We use list(set(...)) to remove duplicates. - res_ids = list(set(old_values[key]['value'][field_name] + new_values[key]['value'][field_name])) + # need to log also creation or deletion in those lists). + x2m_old_values_ids = old_values.get(key, {'value': {}})['value'].get(field_name, []) + x2m_new_values_ids = new_values.get(key, {'value': {}})['value'].get(field_name, []) + # We use list(set(...)) to remove duplicates. + res_ids = list(set(x2m_old_values_ids + x2m_new_values_ids)) for res_id in res_ids: - lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, res_id, method, old_values, new_values)) + lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, res_id, method, old_values, new_values, field_list)) # if the value value is different than the old value: record the change if key not in old_values or key not in new_values or old_values[key]['value'][field_name] != new_values[key]['value'][field_name]: data = { @@ -448,7 +414,7 @@ class audittrail_objects_proxy(object_proxy): lines[key].append(data) return lines - def process_data(self, cr, uid, pool, res_ids, model, method, old_values={}, new_values={}): + def process_data(self, cr, uid, pool, res_ids, model, method, old_values={}, new_values={}, field_list=[]): """ This function processes and iterates recursively to log the difference between the old data (i.e before the method was executed) and the new data and creates audittrail log @@ -462,12 +428,15 @@ class audittrail_objects_proxy(object_proxy): :param method: method to log: create, read, unlink, write, actions, workflow actions :param old_values: dict of values read before execution of the method :param new_values: dict of values read after execution of the method + :param field_list: optional argument containing the list of fields to log. Currently only + used when performing a read, it could be usefull later on if we want to log the write + on specific fields only. :return: True """ # loop on all the given ids for res_id in res_ids: # compare old and new values and get audittrail log lines accordingly - lines = self.prepare_audittrail_log_line(cr, uid, pool, model, res_id, method, old_values, new_values) + lines = self.prepare_audittrail_log_line(cr, uid, pool, model, res_id, method, old_values, new_values, field_list) # if at least one modification has been found for model_id, resource_id in lines: @@ -477,12 +446,12 @@ class audittrail_objects_proxy(object_proxy): 'user_id': uid, 'res_id': resource_id, } - if (model_id, resource_id) not in old_values and method !='copy': + if (model_id, resource_id) not in old_values and method not in ('copy', 'read'): # the resource was not existing so we are forcing the method to 'create' # (because it could also come with the value 'write' if we are creating # new record through a one2many field) vals.update({'method': 'create'}) - if (model_id, resource_id) not in new_values and method !='copy': + if (model_id, resource_id) not in new_values and method not in ('copy', 'read'): # the resource is not existing anymore so we are forcing the method to 'unlink' # (because it could also come with the value 'write' if we are deleting the # record through a one2many field) From a8437d1e5892c2efef2724c985690d21ccbbf01c Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 17:20:32 +0100 Subject: [PATCH 25/26] [REF] audittrail: refactoring of audittrail module. added few comments bzr revid: qdp-launchpad@openerp.com-20111121162032-st1jejch7nrrfj86 --- addons/audittrail/audittrail.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index d26d43f00e5..0b39a71fce7 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -244,7 +244,7 @@ class audittrail_objects_proxy(object_proxy): """ Logging function: This function is performing the logging operation @param model: Object whose values are being changed - @param method: method to log: create, read, write, unlink + @param method: method to log: create, read, write, unlink, action or workflow action @param fct_src: execute method of Object proxy @return: Returns result as per method of Object proxy @@ -256,45 +256,47 @@ class audittrail_objects_proxy(object_proxy): model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) model = model_pool.browse(cr, 1, model_id) + + # fields to log. currently only used by log on read() field_list = [] + old_values = new_values = {} if method == 'create': - old_values = {} res = fct_src(cr, uid_orig, model.model, method, *args) if res: res_ids = [res] new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) elif method == 'read': - new_values = {} - old_values = {} res = fct_src(cr, uid_orig, model.model, method, *args) - field_list = args[1] + # build the res_ids and the old_values dict. Here we don't use get_data() to + # avoid performing an additional read() res_ids = [] for record in res: res_ids.append(record['id']) old_values[(model.id, record['id'])] = {'value': record, 'text': record} + # log only the fields read + field_list = args[1] elif method == 'unlink': res_ids = args[0] old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) res = fct_src(cr, uid_orig, model.model, method, *args) - new_values = {} - else: #method is write, action or workflow action + else: # method is write, action or workflow action res_ids = [] if args: res_ids = args[0] if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: - #store the old values into a dictionary + # store the old values into a dictionary old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) - #process the original function, workflow trigger... + # process the original function, workflow trigger... res = fct_src(cr, uid_orig, model.model, method, *args) if method == 'copy': res_ids = [res] if res_ids: - #check the new values and store them into a dictionary + # check the new values and store them into a dictionary new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) - #compare the old and new values and create audittrail log if needed + # compare the old and new values and create audittrail log if needed self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values, field_list) return res From 42bc324cb78ed28a682b4c3b20b06536fcdf2bfb Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 17:27:12 +0100 Subject: [PATCH 26/26] [REF] audittrail: refactoring of audittrail module. fixed a forgotten 'extra and removed' paramater in function call + improved search view bzr revid: qdp-launchpad@openerp.com-20111121162712-wqvcc24nm5fci591 --- addons/audittrail/audittrail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 0b39a71fce7..302d6e146bd 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -332,7 +332,7 @@ class audittrail_objects_proxy(object_proxy): continue values[field] = resource[field] # get the textual value of that field for this record - values_text[field] = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) + values_text[field] = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field]) field_obj = resource_pool._all_columns.get(field).column if field_obj._type in ('one2many','many2many'):