diff --git a/auditlog/README.rst b/auditlog/README.rst index 3502d5978..70d38a77d 100644 --- a/auditlog/README.rst +++ b/auditlog/README.rst @@ -22,8 +22,6 @@ Known issues / Roadmap ====================== * log only operations triggered by some users (currently it logs all users) - * group logs by HTTP query (thanks to werzeug)? - * group HTTP query by user session? Bug Tracker diff --git a/auditlog/__openerp__.py b/auditlog/__openerp__.py index 0299346a2..517fa4f0f 100644 --- a/auditlog/__openerp__.py +++ b/auditlog/__openerp__.py @@ -21,8 +21,9 @@ { 'name': "Audit Log", - 'version': "8.0.1.0.0", + 'version': "8.0.1.1.0", 'author': "ABF OSIELL,Odoo Community Association (OCA)", + 'license': "AGPL-3", 'website': "http://www.osiell.com", 'category': "Tools", 'depends': [ @@ -31,6 +32,8 @@ 'data': [ 'security/ir.model.access.csv', 'views/auditlog_view.xml', + 'views/http_session_view.xml', + 'views/http_request_view.xml', ], 'application': True, 'installable': True, diff --git a/auditlog/models/__init__.py b/auditlog/models/__init__.py index eb562a4c0..e71197ade 100644 --- a/auditlog/models/__init__.py +++ b/auditlog/models/__init__.py @@ -20,4 +20,6 @@ ############################################################################## from . import rule +from . import http_session +from . import http_request from . import log diff --git a/auditlog/models/http_request.py b/auditlog/models/http_request.py new file mode 100644 index 000000000..7d6b19d48 --- /dev/null +++ b/auditlog/models/http_request.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015 ABF OSIELL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api +from openerp.http import request + + +class AuditlogHTTPRequest(models.Model): + _name = 'auditlog.http.request' + _description = u"Auditlog - HTTP request log" + _order = "create_date DESC" + _rec_name = 'display_name' + + display_name = fields.Char(u"Name", compute="_display_name") + name = fields.Char(u"Path") + root_url = fields.Char(u"Root URL") + user_id = fields.Many2one( + 'res.users', string=u"User") + http_session_id = fields.Many2one( + 'auditlog.http.session', string=u"Session") + user_context = fields.Char(u"Context") + log_ids = fields.One2many( + 'auditlog.log', 'http_request_id', string=u"Logs") + + @api.multi + def _display_name(self): + for httprequest in self: + create_date = fields.Datetime.from_string(httprequest.create_date) + tz_create_date = fields.Datetime.context_timestamp( + httprequest, create_date) + httprequest.display_name = u"%s (%s)" % ( + httprequest.name or '?', + fields.Datetime.to_string(tz_create_date)) + + @api.model + def current_http_request(self): + """Create a log corresponding to the current HTTP request, and returns + its ID. This method can be called several times during the + HTTP query/response cycle, it will only log the request on the + first call. + If no HTTP request is available, returns `False`. + """ + if not request: + return False + http_session_model = self.env['auditlog.http.session'] + httprequest = request.httprequest + if httprequest: + if hasattr(httprequest, 'auditlog_http_request_id'): + return httprequest.auditlog_http_request_id + vals = { + 'name': httprequest.path, + 'root_url': httprequest.url_root, + 'user_id': request.uid, + 'http_session_id': http_session_model.current_http_session(), + 'user_context': request.context, + } + httprequest.auditlog_http_request_id = self.create(vals).id + return httprequest.auditlog_http_request_id + return False diff --git a/auditlog/models/http_session.py b/auditlog/models/http_session.py new file mode 100644 index 000000000..046a10fa7 --- /dev/null +++ b/auditlog/models/http_session.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015 ABF OSIELL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api +from openerp.http import request + + +class AuditlogtHTTPSession(models.Model): + _name = 'auditlog.http.session' + _description = u"Auditlog - HTTP User session log" + _order = "create_date DESC" + _rec_name = 'display_name' + + display_name = fields.Char(u"Name", compute="_display_name") + name = fields.Char(u"Session ID") + user_id = fields.Many2one( + 'res.users', string=u"User") + http_request_ids = fields.One2many( + 'auditlog.http.request', 'http_session_id', string=u"HTTP Requests") + + @api.multi + def _display_name(self): + for httpsession in self: + create_date = fields.Datetime.from_string(httpsession.create_date) + tz_create_date = fields.Datetime.context_timestamp( + httpsession, create_date) + httpsession.display_name = u"%s (%s)" % ( + httpsession.user_id and httpsession.user_id.name or '?', + fields.Datetime.to_string(tz_create_date)) + + @api.model + def current_http_session(self): + """Create a log corresponding to the current HTTP user session, and + returns its ID. This method can be called several times during the + HTTP query/response cycle, it will only log the user session on the + first call. + If no HTTP user session is available, returns `False`. + """ + if not request: + return False + httpsession = request.httpsession + if httpsession: + existing_session = self.search( + [('name', '=', httpsession.sid), + ('user_id', '=', request.uid)]) + if existing_session: + return existing_session.id + vals = { + 'name': httpsession.sid, + 'user_id': request.uid, + } + httpsession.auditlog_http_session_id = self.create(vals).id + return httpsession.auditlog_http_session_id + return False diff --git a/auditlog/models/log.py b/auditlog/models/log.py index b222c470e..e8b35ad44 100644 --- a/auditlog/models/log.py +++ b/auditlog/models/log.py @@ -22,7 +22,7 @@ from openerp import models, fields -class auditlog_log(models.Model): +class AuditlogLog(models.Model): _name = 'auditlog.log' _description = "Auditlog - Log" _order = "create_date desc" @@ -36,9 +36,13 @@ class auditlog_log(models.Model): method = fields.Char(u"Method", size=64) line_ids = fields.One2many( 'auditlog.log.line', 'log_id', string=u"Fields updated") + http_session_id = fields.Many2one( + 'auditlog.http.session', string=u"Session") + http_request_id = fields.Many2one( + 'auditlog.http.request', string=u"HTTP Request") -class auditlog_log_line(models.Model): +class AuditlogLogLine(models.Model): _name = 'auditlog.log.line' _description = "Auditlog - Log details (fields updated)" diff --git a/auditlog/models/rule.py b/auditlog/models/rule.py index 4f18c4a3e..7fa4403ec 100644 --- a/auditlog/models/rule.py +++ b/auditlog/models/rule.py @@ -58,7 +58,7 @@ class DictDiffer(object): if self.past_dict[o] == self.current_dict[o]) -class auditlog_rule(models.Model): +class AuditlogRule(models.Model): _name = 'auditlog.rule' _description = "Auditlog - Rule" @@ -110,7 +110,7 @@ class auditlog_rule(models.Model): def _register_hook(self, cr, ids=None): """Get all rules and apply them to log method calls.""" - super(auditlog_rule, self)._register_hook(cr) + super(AuditlogRule, self)._register_hook(cr) if not hasattr(self.pool, '_auditlog_field_cache'): self.pool._auditlog_field_cache = {} if not hasattr(self.pool, '_auditlog_model_cache'): @@ -182,7 +182,7 @@ class auditlog_rule(models.Model): # errors occurs with the `_register_hook()` BaseModel method. def create(self, cr, uid, vals, context=None): """Update the registry when a new rule is created.""" - res_id = super(auditlog_rule, self).create( + res_id = super(AuditlogRule, self).create( cr, uid, vals, context=context) if self._register_hook(cr, [res_id]): modules.registry.RegistryManager.signal_registry_change(cr.dbname) @@ -194,7 +194,7 @@ class auditlog_rule(models.Model): """Update the registry when existing rules are updated.""" if isinstance(ids, (int, long)): ids = [ids] - super(auditlog_rule, self).write(cr, uid, ids, vals, context=context) + super(AuditlogRule, self).write(cr, uid, ids, vals, context=context) if self._register_hook(cr, ids): modules.registry.RegistryManager.signal_registry_change(cr.dbname) return True @@ -203,7 +203,7 @@ class auditlog_rule(models.Model): def unlink(self): """Unsubscribe rules before removing them.""" self.unsubscribe() - return super(auditlog_rule, self).unlink() + return super(AuditlogRule, self).unlink() def _make_create(self): """Instanciate a create method that log its calls.""" @@ -306,6 +306,8 @@ class auditlog_rule(models.Model): if new_values is None: new_values = EMPTY_DICT log_model = self.env['auditlog.log'] + http_request_model = self.env['auditlog.http.request'] + http_session_model = self.env['auditlog.http.session'] for res_id in res_ids: model_model = self.env[res_model] name = model_model.browse(res_id).name_get() @@ -316,6 +318,8 @@ class auditlog_rule(models.Model): 'res_id': res_id, 'method': method, 'user_id': uid, + 'http_request_id': http_request_model.current_http_request(), + 'http_session_id': http_session_model.current_http_session(), } vals.update(additional_log_values or {}) log = log_model.create(vals) diff --git a/auditlog/security/ir.model.access.csv b/auditlog/security/ir.model.access.csv index 1bb8381d0..32744cc21 100644 --- a/auditlog/security/ir.model.access.csv +++ b/auditlog/security/ir.model.access.csv @@ -2,7 +2,11 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_auditlog_rule_user,auditlog_rule_user,model_auditlog_rule,base.group_user,0,0,0,0 access_auditlog_log_user,auditlog_log_user,model_auditlog_log,base.group_user,0,0,0,0 access_auditlog_log_line_user,auditlog_log_line_user,model_auditlog_log_line,base.group_user,0,0,0,0 +access_auditlog_http_session_user,auditlog_http_session_user,model_auditlog_http_session,base.group_user,0,0,0,0 +access_auditlog_http_request_user,auditlog_http_request_user,model_auditlog_http_request,base.group_user,0,0,0,0 access_auditlog_rule_manager,auditlog_rule_manager,model_auditlog_rule,base.group_erp_manager,1,1,1,1 access_auditlog_log_manager,auditlog_log_manager,model_auditlog_log,base.group_erp_manager,1,1,1,1 access_auditlog_log_line_manager,auditlog_log_line_manager,model_auditlog_log_line,base.group_erp_manager,1,1,1,1 +access_auditlog_http_session_manager,auditlog_http_session_manager,model_auditlog_http_session,base.group_erp_manager,1,1,1,1 +access_auditlog_http_request_manager,auditlog_http_request_manager,model_auditlog_http_request,base.group_erp_manager,1,1,1,1 diff --git a/auditlog/views/auditlog_view.xml b/auditlog/views/auditlog_view.xml index 5bf2132cb..db0a5de81 100644 --- a/auditlog/views/auditlog_view.xml +++ b/auditlog/views/auditlog_view.xml @@ -117,6 +117,10 @@ + + + +
@@ -182,6 +186,12 @@ + + diff --git a/auditlog/views/http_request_view.xml b/auditlog/views/http_request_view.xml new file mode 100644 index 000000000..2169ed0f9 --- /dev/null +++ b/auditlog/views/http_request_view.xml @@ -0,0 +1,82 @@ + + + + + + auditlog.http.request.form + auditlog.http.request + + + + + + + + + + + + + + + + + + + + auditlog.http.request.tree + auditlog.http.request + + + + + + + + + + + auditlog.http.request.search + auditlog.http.request + + + + + + + + + + + + + + + + + + + + HTTP Requests + ir.actions.act_window + auditlog.http.request + form + + + + + + + diff --git a/auditlog/views/http_session_view.xml b/auditlog/views/http_session_view.xml new file mode 100644 index 000000000..942da68af --- /dev/null +++ b/auditlog/views/http_session_view.xml @@ -0,0 +1,69 @@ + + + + + + auditlog.http.session.form + auditlog.http.session + +
+ + + + + + + + + + +
+
+
+ + + auditlog.http.session.tree + auditlog.http.session + + + + + + + + + + + auditlog.http.session.search + auditlog.http.session + + + + + + + + + + + + + + + User sessions + ir.actions.act_window + auditlog.http.session + form + + + + + +
+