List, form, and search views for fusion.login.audit, plus a "Login Events" full-history action and a "Failed Logins (24h)" pre-filtered action. Both surface under Settings -> Technical -> Login Audit (menu items gated by base.group_system). Views are no-create / no-edit / no-delete to enforce append-only at the UI layer too. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
119 lines
5.6 KiB
XML
119 lines
5.6 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
|
|
<!-- List -->
|
|
<record id="view_fusion_login_audit_list" model="ir.ui.view">
|
|
<field name="name">fusion.login.audit.list</field>
|
|
<field name="model">fusion.login.audit</field>
|
|
<field name="arch" type="xml">
|
|
<list create="false" edit="false" delete="false"
|
|
default_order="event_time desc"
|
|
decoration-success="result=='success'"
|
|
decoration-danger="result=='failure'">
|
|
<field name="event_time"/>
|
|
<field name="user_id"/>
|
|
<field name="attempted_login"/>
|
|
<field name="result" widget="badge"/>
|
|
<field name="failure_reason"/>
|
|
<field name="ip_address"/>
|
|
<field name="country_code"/>
|
|
<field name="city"/>
|
|
<field name="browser"/>
|
|
<field name="device_type"/>
|
|
<field name="database" optional="hide"/>
|
|
</list>
|
|
</field>
|
|
</record>
|
|
|
|
<!-- Form (readonly) -->
|
|
<record id="view_fusion_login_audit_form" model="ir.ui.view">
|
|
<field name="name">fusion.login.audit.form</field>
|
|
<field name="model">fusion.login.audit</field>
|
|
<field name="arch" type="xml">
|
|
<form create="false" edit="false" delete="false">
|
|
<sheet>
|
|
<group>
|
|
<group string="Event">
|
|
<field name="event_time" readonly="1"/>
|
|
<field name="result" readonly="1" widget="badge"/>
|
|
<field name="failure_reason" readonly="1"/>
|
|
<field name="user_id" readonly="1"/>
|
|
<field name="attempted_login" readonly="1"/>
|
|
<field name="database" readonly="1"/>
|
|
</group>
|
|
<group string="Source">
|
|
<field name="ip_address" readonly="1"/>
|
|
<field name="ip_hostname" readonly="1"/>
|
|
<field name="country_code" readonly="1"/>
|
|
<field name="country_name" readonly="1"/>
|
|
<field name="geo_state" readonly="1"/>
|
|
<field name="city" readonly="1"/>
|
|
<field name="geo_lookup_state" readonly="1"/>
|
|
</group>
|
|
</group>
|
|
<group string="Client">
|
|
<field name="device_type" readonly="1"/>
|
|
<field name="browser" readonly="1"/>
|
|
<field name="os" readonly="1"/>
|
|
<field name="user_agent_raw" readonly="1"/>
|
|
</group>
|
|
</sheet>
|
|
</form>
|
|
</field>
|
|
</record>
|
|
|
|
<!-- Search -->
|
|
<record id="view_fusion_login_audit_search" model="ir.ui.view">
|
|
<field name="name">fusion.login.audit.search</field>
|
|
<field name="model">fusion.login.audit</field>
|
|
<field name="arch" type="xml">
|
|
<search>
|
|
<field name="attempted_login"/>
|
|
<field name="user_id"/>
|
|
<field name="ip_address"/>
|
|
<field name="country_code"/>
|
|
<filter name="filter_success" string="Successes"
|
|
domain="[('result','=','success')]"/>
|
|
<filter name="filter_failure" string="Failures"
|
|
domain="[('result','=','failure')]"/>
|
|
<separator/>
|
|
<filter name="filter_24h" string="Last 24 hours"
|
|
domain="[('event_time','>=', (context_today() - relativedelta(days=1)).strftime('%Y-%m-%d 00:00:00'))]"/>
|
|
<filter name="filter_7d" string="Last 7 days"
|
|
domain="[('event_time','>=', (context_today() - relativedelta(days=7)).strftime('%Y-%m-%d 00:00:00'))]"/>
|
|
<filter name="filter_30d" string="Last 30 days"
|
|
domain="[('event_time','>=', (context_today() - relativedelta(days=30)).strftime('%Y-%m-%d 00:00:00'))]"/>
|
|
<separator/>
|
|
<filter name="filter_unknown_user" string="Unknown users"
|
|
domain="[('user_id','=',False)]"/>
|
|
<group>
|
|
<filter name="group_user" string="User"
|
|
context="{'group_by': 'user_id'}"/>
|
|
<filter name="group_country" string="Country"
|
|
context="{'group_by': 'country_code'}"/>
|
|
<filter name="group_ip" string="IP"
|
|
context="{'group_by': 'ip_address'}"/>
|
|
</group>
|
|
</search>
|
|
</field>
|
|
</record>
|
|
|
|
<!-- Window actions -->
|
|
<record id="action_fusion_login_audit_all" model="ir.actions.act_window">
|
|
<field name="name">Login Events</field>
|
|
<field name="res_model">fusion.login.audit</field>
|
|
<field name="view_mode">list,form</field>
|
|
<field name="search_view_id" ref="view_fusion_login_audit_search"/>
|
|
<field name="context">{}</field>
|
|
</record>
|
|
|
|
<record id="action_fusion_login_audit_failures_24h" model="ir.actions.act_window">
|
|
<field name="name">Failed Logins (24h)</field>
|
|
<field name="res_model">fusion.login.audit</field>
|
|
<field name="view_mode">list,form</field>
|
|
<field name="search_view_id" ref="view_fusion_login_audit_search"/>
|
|
<field name="context">{'search_default_filter_failure': 1, 'search_default_filter_24h': 1}</field>
|
|
</record>
|
|
|
|
</odoo>
|