Files
Odoo-Modules/fusion_login_audit/views/fusion_login_audit_views.xml
gsinghpal 0513ea23a4 feat(fusion_login_audit): standalone views + menus
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>
2026-05-27 09:03:59 -04:00

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','&gt;=', (context_today() - relativedelta(days=1)).strftime('%Y-%m-%d 00:00:00'))]"/>
<filter name="filter_7d" string="Last 7 days"
domain="[('event_time','&gt;=', (context_today() - relativedelta(days=7)).strftime('%Y-%m-%d 00:00:00'))]"/>
<filter name="filter_30d" string="Last 30 days"
domain="[('event_time','&gt;=', (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>