Browse Source

Merge pull request #284 from osiell/auditlog_http

[8.0] Module 'auditlog' - Log HTTP user sessions and requests
pull/301/head
Alexandre Fayolle 9 years ago
parent
commit
5004a7fbaf
  1. 2
      auditlog/README.rst
  2. 5
      auditlog/__openerp__.py
  3. 2
      auditlog/models/__init__.py
  4. 77
      auditlog/models/http_request.py
  5. 72
      auditlog/models/http_session.py
  6. 8
      auditlog/models/log.py
  7. 14
      auditlog/models/rule.py
  8. 4
      auditlog/security/ir.model.access.csv
  9. 10
      auditlog/views/auditlog_view.xml
  10. 82
      auditlog/views/http_request_view.xml
  11. 69
      auditlog/views/http_session_view.xml

2
auditlog/README.rst

@ -22,8 +22,6 @@ Known issues / Roadmap
====================== ======================
* log only operations triggered by some users (currently it logs all users) * 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 Bug Tracker

5
auditlog/__openerp__.py

@ -21,8 +21,9 @@
{ {
'name': "Audit Log", 'name': "Audit Log",
'version': "8.0.1.0.0",
'version': "8.0.1.1.0",
'author': "ABF OSIELL,Odoo Community Association (OCA)", 'author': "ABF OSIELL,Odoo Community Association (OCA)",
'license': "AGPL-3",
'website': "http://www.osiell.com", 'website': "http://www.osiell.com",
'category': "Tools", 'category': "Tools",
'depends': [ 'depends': [
@ -31,6 +32,8 @@
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'views/auditlog_view.xml', 'views/auditlog_view.xml',
'views/http_session_view.xml',
'views/http_request_view.xml',
], ],
'application': True, 'application': True,
'installable': True, 'installable': True,

2
auditlog/models/__init__.py

@ -20,4 +20,6 @@
############################################################################## ##############################################################################
from . import rule from . import rule
from . import http_session
from . import http_request
from . import log from . import log

77
auditlog/models/http_request.py

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2015 ABF OSIELL (<http://osiell.com>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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

72
auditlog/models/http_session.py

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2015 ABF OSIELL (<http://osiell.com>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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

8
auditlog/models/log.py

@ -22,7 +22,7 @@
from openerp import models, fields from openerp import models, fields
class auditlog_log(models.Model):
class AuditlogLog(models.Model):
_name = 'auditlog.log' _name = 'auditlog.log'
_description = "Auditlog - Log" _description = "Auditlog - Log"
_order = "create_date desc" _order = "create_date desc"
@ -36,9 +36,13 @@ class auditlog_log(models.Model):
method = fields.Char(u"Method", size=64) method = fields.Char(u"Method", size=64)
line_ids = fields.One2many( line_ids = fields.One2many(
'auditlog.log.line', 'log_id', string=u"Fields updated") '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' _name = 'auditlog.log.line'
_description = "Auditlog - Log details (fields updated)" _description = "Auditlog - Log details (fields updated)"

14
auditlog/models/rule.py

@ -58,7 +58,7 @@ class DictDiffer(object):
if self.past_dict[o] == self.current_dict[o]) if self.past_dict[o] == self.current_dict[o])
class auditlog_rule(models.Model):
class AuditlogRule(models.Model):
_name = 'auditlog.rule' _name = 'auditlog.rule'
_description = "Auditlog - Rule" _description = "Auditlog - Rule"
@ -110,7 +110,7 @@ class auditlog_rule(models.Model):
def _register_hook(self, cr, ids=None): def _register_hook(self, cr, ids=None):
"""Get all rules and apply them to log method calls.""" """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'): if not hasattr(self.pool, '_auditlog_field_cache'):
self.pool._auditlog_field_cache = {} self.pool._auditlog_field_cache = {}
if not hasattr(self.pool, '_auditlog_model_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. # errors occurs with the `_register_hook()` BaseModel method.
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
"""Update the registry when a new rule is created.""" """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) cr, uid, vals, context=context)
if self._register_hook(cr, [res_id]): if self._register_hook(cr, [res_id]):
modules.registry.RegistryManager.signal_registry_change(cr.dbname) 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.""" """Update the registry when existing rules are updated."""
if isinstance(ids, (int, long)): if isinstance(ids, (int, long)):
ids = [ids] 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): if self._register_hook(cr, ids):
modules.registry.RegistryManager.signal_registry_change(cr.dbname) modules.registry.RegistryManager.signal_registry_change(cr.dbname)
return True return True
@ -203,7 +203,7 @@ class auditlog_rule(models.Model):
def unlink(self): def unlink(self):
"""Unsubscribe rules before removing them.""" """Unsubscribe rules before removing them."""
self.unsubscribe() self.unsubscribe()
return super(auditlog_rule, self).unlink()
return super(AuditlogRule, self).unlink()
def _make_create(self): def _make_create(self):
"""Instanciate a create method that log its calls.""" """Instanciate a create method that log its calls."""
@ -306,6 +306,8 @@ class auditlog_rule(models.Model):
if new_values is None: if new_values is None:
new_values = EMPTY_DICT new_values = EMPTY_DICT
log_model = self.env['auditlog.log'] 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: for res_id in res_ids:
model_model = self.env[res_model] model_model = self.env[res_model]
name = model_model.browse(res_id).name_get() name = model_model.browse(res_id).name_get()
@ -316,6 +318,8 @@ class auditlog_rule(models.Model):
'res_id': res_id, 'res_id': res_id,
'method': method, 'method': method,
'user_id': uid, '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 {}) vals.update(additional_log_values or {})
log = log_model.create(vals) log = log_model.create(vals)

4
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_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_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_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_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_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_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

10
auditlog/views/auditlog_view.xml

@ -117,6 +117,10 @@
<field name="name" readonly="1"/> <field name="name" readonly="1"/>
</group> </group>
</group> </group>
<group string="HTTP Context">
<field name="http_session_id"/>
<field name="http_request_id"/>
</group>
<group string="Fields updated"> <group string="Fields updated">
<field name="line_ids" readonly="1" nolabel="1"> <field name="line_ids" readonly="1" nolabel="1">
<form string="Log - Field updated"> <form string="Log - Field updated">
@ -182,6 +186,12 @@
<filter name="group_by_create_date" <filter name="group_by_create_date"
string="Date" string="Date"
domain="[]" context="{'group_by':'create_date'}"/> domain="[]" context="{'group_by':'create_date'}"/>
<filter name="group_by_http_session"
string="User session"
domain="[]" context="{'group_by':'http_session_id'}"/>
<filter name="group_by_http_request"
string="HTTP Request"
domain="[]" context="{'group_by':'http_request_id'}"/>
</group> </group>
</search> </search>
</field> </field>

82
auditlog/views/http_request_view.xml

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_auditlog_http_request_form" model="ir.ui.view">
<field name="name">auditlog.http.request.form</field>
<field name="model">auditlog.http.request</field>
<field name="arch" type="xml">
<form string="HTTP Request">
<sheet>
<group string="HTTP Request">
<field name="root_url"/>
<field name="name"/>
<field name="create_date"/>
<field name="user_context"/>
<field name="http_session_id"/>
</group>
<group string="Logs">
<field name="log_ids" nolabel="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_auditlog_http_request_tree" model="ir.ui.view">
<field name="name">auditlog.http.request.tree</field>
<field name="model">auditlog.http.request</field>
<field name="arch" type="xml">
<tree string="HTTP Requests">
<field name="name"/>
<field name="create_date"/>
<field name="http_session_id"/>
</tree>
</field>
</record>
<record id="view_auditlog_http_request_search" model="ir.ui.view">
<field name="name">auditlog.http.request.search</field>
<field name="model">auditlog.http.request</field>
<field name="arch" type="xml">
<search string="HTTP Requests">
<field name="create_date"/>
<field name="root_url"/>
<field name="name"/>
<field name="user_id"/>
<field name="http_session_id"/>
<group expand="0" string="Group By...">
<filter name="group_by_root_url"
string="Root URL"
domain="[]" context="{'group_by':'root_url'}"/>
<filter name="group_by_name"
string="Path"
domain="[]" context="{'group_by':'name'}"/>
<filter name="group_by_create_date"
string="Created on"
domain="[]" context="{'group_by':'create_date'}"/>
<filter name="group_by_user_id"
string="User"
domain="[]" context="{'group_by':'user_id'}"/>
<filter name="group_by_http_session_id"
string="User session"
domain="[]" context="{'group_by':'http_session_id'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_auditlog_http_request_tree">
<field name="name">HTTP Requests</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">auditlog.http.request</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_auditlog_http_request_tree"/>
</record>
<menuitem id="menu_action_auditlog_http_request_tree"
parent="menu_audit"
action="action_auditlog_http_request_tree"/>
</data>
</openerp>

69
auditlog/views/http_session_view.xml

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_auditlog_http_session_form" model="ir.ui.view">
<field name="name">auditlog.http.session.form</field>
<field name="model">auditlog.http.session</field>
<field name="arch" type="xml">
<form string="User session">
<sheet>
<group string="User session">
<field name="user_id"/>
<field name="create_date"/>
<field name="name"/>
</group>
<group string="HTTP Requests">
<field name="http_request_ids" nolabel="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_auditlog_http_session_tree" model="ir.ui.view">
<field name="name">auditlog.http.session.tree</field>
<field name="model">auditlog.http.session</field>
<field name="arch" type="xml">
<tree string="User sessions">
<field name="user_id"/>
<field name="create_date"/>
<field name="name"/>
</tree>
</field>
</record>
<record id="view_auditlog_http_session_search" model="ir.ui.view">
<field name="name">auditlog.http.session.search</field>
<field name="model">auditlog.http.session</field>
<field name="arch" type="xml">
<search string="User sessions">
<field name="user_id"/>
<field name="name"/>
<field name="create_date"/>
<group expand="0" string="Group By...">
<filter name="group_by_user_id"
string="User"
domain="[]" context="{'group_by':'user_id'}"/>
<filter name="group_by_create_date"
string="Created on"
domain="[]" context="{'group_by':'create_date'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_auditlog_http_session_tree">
<field name="name">User sessions</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">auditlog.http.session</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_auditlog_http_session_tree"/>
</record>
<menuitem id="menu_action_auditlog_http_session_tree"
parent="menu_audit"
action="action_auditlog_http_session_tree"/>
</data>
</openerp>
Loading…
Cancel
Save