Browse Source

Jan 16 [ADD] : Initial Commit 'user_session_management'

pull/254/merge
AjmalCybro 1 year ago
parent
commit
3bdcd648d5
  1. 48
      user_session_management/README.rst
  2. 23
      user_session_management/__init__.py
  3. 57
      user_session_management/__manifest__.py
  4. 22
      user_session_management/controllers/__init__.py
  5. 88
      user_session_management/controllers/user_session_management.py
  6. 16
      user_session_management/data/ir_cron_data.xml
  7. 13
      user_session_management/data/ir_sequence_data.xml
  8. 6
      user_session_management/doc/RELEASE_NOTES.md
  9. 27
      user_session_management/models/__init__.py
  10. 174
      user_session_management/models/base.py
  11. 46
      user_session_management/models/ir_http.py
  12. 72
      user_session_management/models/res_config_settings.py
  13. 36
      user_session_management/models/res_users.py
  14. 56
      user_session_management/models/user_session_activity.py
  15. 146
      user_session_management/models/user_session_login.py
  16. 7
      user_session_management/security/ir.model.access.csv
  17. 18
      user_session_management/security/user_session_management_groups.xml
  18. 39
      user_session_management/security/user_session_management_security.xml
  19. BIN
      user_session_management/static/description/assets/icons/check.png
  20. BIN
      user_session_management/static/description/assets/icons/chevron.png
  21. BIN
      user_session_management/static/description/assets/icons/cogs.png
  22. BIN
      user_session_management/static/description/assets/icons/consultation.png
  23. BIN
      user_session_management/static/description/assets/icons/ecom-black.png
  24. BIN
      user_session_management/static/description/assets/icons/education-black.png
  25. BIN
      user_session_management/static/description/assets/icons/hotel-black.png
  26. BIN
      user_session_management/static/description/assets/icons/license.png
  27. BIN
      user_session_management/static/description/assets/icons/lifebuoy.png
  28. BIN
      user_session_management/static/description/assets/icons/logo.png
  29. BIN
      user_session_management/static/description/assets/icons/manufacturing-black.png
  30. BIN
      user_session_management/static/description/assets/icons/pos-black.png
  31. BIN
      user_session_management/static/description/assets/icons/puzzle.png
  32. BIN
      user_session_management/static/description/assets/icons/restaurant-black.png
  33. BIN
      user_session_management/static/description/assets/icons/service-black.png
  34. BIN
      user_session_management/static/description/assets/icons/trading-black.png
  35. BIN
      user_session_management/static/description/assets/icons/training.png
  36. BIN
      user_session_management/static/description/assets/icons/update.png
  37. BIN
      user_session_management/static/description/assets/icons/user.png
  38. BIN
      user_session_management/static/description/assets/icons/wrench.png
  39. BIN
      user_session_management/static/description/assets/modules/budget_image.png
  40. BIN
      user_session_management/static/description/assets/modules/credit_image.png
  41. BIN
      user_session_management/static/description/assets/modules/employee_image.png
  42. BIN
      user_session_management/static/description/assets/modules/export_image.png
  43. BIN
      user_session_management/static/description/assets/modules/gantt_image.png
  44. BIN
      user_session_management/static/description/assets/modules/quotation_image.png
  45. BIN
      user_session_management/static/description/assets/screenshots/activities.png
  46. BIN
      user_session_management/static/description/assets/screenshots/conf_settings.png
  47. BIN
      user_session_management/static/description/assets/screenshots/hero.gif
  48. BIN
      user_session_management/static/description/assets/screenshots/log_out.png
  49. BIN
      user_session_management/static/description/assets/screenshots/login.png
  50. BIN
      user_session_management/static/description/assets/screenshots/session_form.png
  51. BIN
      user_session_management/static/description/assets/screenshots/settings.png
  52. BIN
      user_session_management/static/description/banner.png
  53. BIN
      user_session_management/static/description/icon.png
  54. 623
      user_session_management/static/description/index.html
  55. 89
      user_session_management/views/res_config_settings_views.xml
  56. 16
      user_session_management/views/res_users_views.xml
  57. 92
      user_session_management/views/user_session_activity_views.xml
  58. 98
      user_session_management/views/user_session_login_views.xml

48
user_session_management/README.rst

@ -0,0 +1,48 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
Odoo User Session Management And Activity Tracking
==================================================
A tool to track the sessions and activities of users.
Configuration
=============
Need to select the models to be tracked in Configuration/Settings.
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
License
-------
GNU AFFERO GENERAL PUBLIC LICENSE, Version 3 (AGPLv3)
(https://www.gnu.org/licenses/agpl.html)
Credits
-------
* Developer: (V15) Abhijith PG, Contact: odoo@cybrosys.com
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if
your issue has already been reported.
Maintainer
==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies.
For support and more information, please visit
`Our Website <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

23
user_session_management/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import controllers
from . import models

57
user_session_management/__manifest__.py

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
{
'name': "Odoo User Session Management And Activity Tracking",
'version': '15.0.1.0.0',
'category': 'Productivity',
'summary': """User session management and activity tracking on each
session.""",
'description': """A tool that can be used to track the sessions and
activities of users in your Odoo system.
The app allows you to view the session details, such as the
login time, IP address, Device, OS, etc. along with activity
tracking """,
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com',
'depends': ['base'],
'data': [
'security/user_session_management_groups.xml',
'security/user_session_management_security.xml',
'security/ir.model.access.csv',
'data/ir_cron_data.xml',
'data/ir_sequence_data.xml',
'views/user_session_login_views.xml',
'views/user_session_activity_views.xml',
'views/res_config_settings_views.xml',
'views/res_users_views.xml',
],
'external_dependencies': {
'python': ['user_agents'],
},
'images': ['static/description/banner.png'],
'license': "AGPL-3",
'installable': True,
'auto_install': False,
'application': False,
}

22
user_session_management/controllers/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import user_session_management

88
user_session_management/controllers/user_session_management.py

@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from user_agents import parse
from odoo import http
from odoo.http import request
from odoo.fields import Datetime
from odoo.addons.web.controllers.main import Home, Session
class Home(Home):
"""Subclass of Home which creates the session data in User Session Login.
When a user logs in successfully, a record is created in the
'user.session.login' with information about the user's session, device,
browser, and IP address.
"""
@http.route()
def web_login(self, redirect=None, **kw):
"""
Overrides the web_login method of Home to create a
user session login record when a user logs in successfully.
"""
res = super().web_login(redirect=redirect, **kw)
if request.params['login_success']:
user = request.env['res.users'].sudo().search(
[('login', '=', kw['login'])], limit=1)
if user:
user.status = 'done'
agent = request.httprequest.environ.get('HTTP_USER_AGENT')
user_agent = parse(agent)
request.env['user.session.login'].create({
'status': 'done',
'user_id': user.id,
'sid': request.session.sid,
'login_date': Datetime.now(),
'device': user_agent.get_device(),
'os': user_agent.os.family,
'browser': user_agent.browser.family,
'ip_address': request.httprequest.environ['REMOTE_ADDR'],
'state': 'active'
})
return res
class Session(Session):
"""Subclass of the Session used to update the user session login record
when a user logs out.
"""
@http.route()
def logout(self, redirect='/web', uid=False, usm_session_id=False):
"""Updates the logout status"""
user = request.env['res.users'].sudo().browse(
[uid or request.session.uid])
if user:
loggedout = request.env['user.session.login'].sudo().search(
[('user_id', '=', user.id), ('logout_date', '=', False),
('id', '=', usm_session_id or request.session.usm_session_id)],
limit=1)
if loggedout:
loggedout.logout_date = Datetime.now()
loggedout.update({
'status': 'blocked',
'state': 'closed'
})
# Updating status indicator
state_mapped = request.env['user.session.login'].sudo().search(
[('user_id', '=', user.id)]).mapped('state')
if 'active' not in state_mapped:
user.status = 'blocked'
return super().logout(redirect=redirect)

16
user_session_management/data/ir_cron_data.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Used for clearing the older records in user.session.login -->
<record id="ir_cron_session_clear_scheduler" model="ir.cron">
<field name="name">Session Clear Scheduler</field>
<field name="model_id" ref="model_user_session_login"/>
<field name="state">code</field>
<field name="code">model.clear_records()</field>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
</record>
</data>
</odoo>

13
user_session_management/data/ir_sequence_data.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Used to create sequence number of records in user.session.login-->
<record id="sequence_user_session_login" model="ir.sequence">
<field name="name">User Session Login Name</field>
<field name="code">user.session.login.name</field>
<field name="prefix">S</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
</data>
</odoo>

6
user_session_management/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <user_session_management>
#### 20.07.2023
#### Version 15.0.1.0.0
#### ADD
- Initial commit for Odoo User Session Management And Activity Tracking

27
user_session_management/models/__init__.py

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import base
from . import ir_http
from . import res_config_settings
from . import res_users
from . import user_session_activity
from . import user_session_login

174
user_session_management/models/base.py

@ -0,0 +1,174 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from ast import literal_eval
from odoo import api, models
from odoo.http import request
class Base(models.AbstractModel):
"""
Inherited Abstract Model to monitor and log user session activities like
record creation, modification, deletion, and read.
"""
_inherit = 'base'
@api.model
def create(self, vals_list):
"""
Overrides the default create method to create a user session activity
log when a record is created.
"""
res = super().create(vals_list)
models_to_track = self.env['ir.config_parameter'].sudo().get_param(
'user_session_management.model_ids')
if models_to_track:
try:
model_ids = self.env['ir.model'].sudo().browse(
literal_eval(models_to_track))
if model_ids and self._name in model_ids.mapped('model'):
name = ''
if self._context.get('params') and self._context[
'params'].get(
'action'):
name = self.env['ir.actions.act_window'].sudo().browse(
self._context['params']['action']).name or ''
if 'name' in vals_list.keys():
name = vals_list['name']
log_vals = {'name': name,
'model': self._name,
'record': res.id,
'action': 'create',
'login_id': request.session.usm_session_id,
}
self.env['user.session.activity'].create(log_vals)
except:
pass
return res
def read(self, fields=None, load='_classic_read', log=True):
"""
Overrides the default read method to create a user session activity
log when a record is read
"""
res = super().read(fields, load)
if log:
models_to_track = self.env['ir.config_parameter'].sudo().get_param(
'user_session_management.model_ids')
if models_to_track:
try:
model_ids = self.env['ir.model'].sudo().browse(
literal_eval(models_to_track))
if model_ids and self._name in model_ids.mapped('model'):
name = ''
if self._context.get('params'):
if self._context['params'].get('action'):
name = self.env['ir.actions.act_window'].sudo()\
.browse(
self._context['params'][
'action']).name or ''
record = False
records = ''
if len(self) == 1:
name = self.name if self._fields.get(
'name') else name
record = self.id
else:
records = self.ids
log_vals = {'name': name,
'model': self._name,
'record': record,
'records': records,
'action': 'read',
'login_id': request.session.usm_session_id,
}
self.env['user.session.activity'].create(log_vals)
except:
pass
return res
def write(self, vals):
"""
Overrides the default write method to create a user session activity
log when a record is modified.
"""
models_to_track = self.env['ir.config_parameter'].sudo().get_param(
'user_session_management.model_ids')
if models_to_track:
try:
model_ids = self.env['ir.model'].browse(
literal_eval(models_to_track))
if model_ids and self._name in model_ids.mapped('model'):
res = super().write(vals)
name = ''
if self._context.get('params') and self._context[
'params'].get('action'):
name = self.env['ir.actions.act_window'].browse(
self._context['params']['action']).name or ''
if 'name' in self._fields.keys():
name = self.name
log_vals = {'name': name,
'model': self._name,
'record': self.id,
'action': 'modify',
'login_id': request.session.usm_session_id,
}
self.env['user.session.activity'].create(log_vals)
return res
except:
pass
return super().write(vals)
def unlink(self):
"""
Overrides the default unlink method to create a user session activity
log when a record is deleted.
"""
models_to_track = self.env['ir.config_parameter'].sudo().get_param(
'user_session_management.model_ids')
if models_to_track:
try:
model_ids = self.env['ir.model'].browse(
literal_eval(models_to_track))
if model_ids and self._name in model_ids.mapped('model'):
name = ''
if self._context.get('params') and self._context[
'params'].get('action'):
name = self.env['ir.actions.act_window'].browse(
self._context['params']['action']).name
record = False
records = ''
if len(self) == 1:
name = self.name if self._fields.get('name') else name
record = self.id
else:
records = self.ids
log_vals = {'name': name,
'model': self._name,
'record': record,
'records': records,
'action': 'delete',
'login_id': request.session.usm_session_id,
}
self.env['user.session.activity'].create(log_vals)
except:
pass
return super().unlink()

46
user_session_management/models/ir_http.py

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models
from odoo.http import request
class IrHttp(models.AbstractModel):
"""
Inherits the 'ir.http' abstract model to override its '_authenticate' method
to update the sid in user.session.login.
"""
_inherit = 'ir.http'
@classmethod
def _authenticate(cls, endpoint):
"""
Overrides odoo.addons.base.models.ir_http._authenticate to update the
sid in user.session.login.
"""
res = super()._authenticate(endpoint)
u_sid = request.session.sid
usm_session_id = request.session.get('usm_session_id')
if usm_session_id:
request.env['user.session.login'].browse(usm_session_id).write({
'sid': u_sid
})
return res

72
user_session_management/models/res_config_settings.py

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from ast import literal_eval
from odoo import api, fields, models
class ResConfigSettings(models.TransientModel):
"""Configuration Settings"""
_inherit = 'res.config.settings'
model_ids = fields.Many2many('ir.model', string='Models',
domain=[('model', 'not in',
['user.session.login',
'user.session.activity'])],
help='Add the models to track.')
clear_log = fields.Boolean(string='Clear Logs Periodically',
help='Select the checkbox to clear the log '
'records automatically')
records_retain_period = fields.Integer(string='Records Retain Period',
help='Number of days after a '
'session ends before its logs '
'will be automatically removed '
'from the system.')
def set_values(self):
"""Update the values of configuration parameters."""
res = super().set_values()
self.env['ir.config_parameter'].set_param(
'user_session_management.model_ids', self.model_ids.ids)
self.env['ir.config_parameter'].set_param(
'user_session_management.clear_log',
self.clear_log)
self.env['ir.config_parameter'].set_param(
'user_session_management.records_retain_period',
self.records_retain_period)
return res
@api.model
def get_values(self):
"""Retrieve the current values of configuration parameters."""
res = super().get_values()
config_param = self.env['ir.config_parameter'].sudo()
tracked_models = config_param.get_param(
'user_session_management.model_ids')
clear_log = config_param.get_param(
'user_session_management.clear_log')
period = config_param.get_param(
'user_session_management.records_retain_period')
res.update(
model_ids=[(6, 0, literal_eval(
tracked_models))] if tracked_models else False,
clear_log=clear_log, records_retain_period=period)
return res

36
user_session_management/models/res_users.py

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class ResUsers(models.Model):
"""
Inherits the `res.users` model and adds a `status` field to represent the
login status of the user.
"""
_inherit = 'res.users'
status = fields.Selection(selection=[
('done', 'Online'),
('blocked', 'Offline'),
], string="Login Status", default='blocked', readonly=1,
help="Login status of the user")

56
user_session_management/models/user_session_activity.py

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class UserSessionActivity(models.Model):
"""
Model to store the user session activities like record creation,
modification, deletion, and read.
"""
_name = "user.session.activity"
_description = "User Session Activity"
name = fields.Char(string='Record Name', readonly=True,
help="Name of the record on which the activity occurred")
user_id = fields.Many2one('res.users', string="User",
default=lambda s: s.env.user.id,
readonly=True, help="Session user")
performed_date = fields.Datetime(string="Performed Date",
default=fields.Datetime.now, readonly=True,
help="Date on which the activity occurred")
model = fields.Char(string="Model", readonly=True,
help="Model on which the activity occurred")
record = fields.Integer(string='Record ID', readonly=True,
help="Record ID on which the activity occurred")
records = fields.Char(string='Record IDs', readonly=True,
help="Record IDs on which the activity occurred")
login_id = fields.Many2one('user.session.login', string='Session',
ondelete='restrict', readonly=True,
help="Session sequence on which the activity"
"occurred")
action = fields.Selection(selection=[('read', 'Read'),
('create', 'Create'),
('modify', 'Modify'),
('delete', 'Delete')],
readonly=True, string="Action",
help="Action performed on the record")

146
user_session_management/models/user_session_login.py

@ -0,0 +1,146 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Abhijith PG (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# 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 (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import pickle
from ast import literal_eval
from datetime import timedelta
import odoo
from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.http import request
from odoo.tools._vendor import sessions
class UserSessionLogin(models.Model):
"""
Model to store user session login information. Contains information like
user_id, login_date, logout_date, session duration, device details,
IP address, etc.
"""
_name = "user.session.login"
_description = "User Session Login"
status = fields.Selection(selection=[('normal', ''),
('done', ''),
('blocked', '')], string='Status',
help="Status of the user session")
name = fields.Char(string='Name', help="Sequence number of the session.")
user_id = fields.Many2one('res.users', string="User", help="Session user")
sid = fields.Char(string='Session ID', help="Session id")
login_date = fields.Datetime(string='Login Date', help="Session login date")
logout_date = fields.Datetime(string='Logout Date',
help="Session logout date")
session_duration = fields.Char(string='Session Duration',
help="Duration of the session",
compute='_compute_session_duration')
device = fields.Char(string='Device',
help="Device from which the session is created")
os = fields.Char(string='OS',
help="Operating System from which the session is created")
browser = fields.Char(string='Browser',
help="Browser on which the session is logged in")
ip_address = fields.Char(string='IP', help="IP address of the device")
state = fields.Selection(selection=[('active', 'Active'),
('closed', 'Closed')],
string='Status', help="State of the session.")
activity_ids = fields.One2many('user.session.activity', 'login_id',
string='Activities',
readonly=True,
help="All the activities in the selected "
"models in the session")
@api.model
def create(self, vals_list):
"""Updating the session sequence when creating a new session record"""
if not vals_list.get('name'):
vals_list['name'] = self.env['ir.sequence'].next_by_code(
'user.session.login.name') or ""
res = super().create(vals_list)
if request and request.session:
request.session.usm_session_id = res.id
return res
@api.depends('login_date', 'logout_date')
def _compute_session_duration(self):
"""Compute session duration"""
self.session_duration = 0
for rec in self:
if rec.login_date and rec.logout_date:
rec.session_duration = str(rec.logout_date - rec.login_date)
else:
rec.session_duration = 0
def unlink(self):
"""
Raises a `ValidationError` if any of the User Session Login records
being deleted have an active session. Only logged-out session user
session records can be deleted.
"""
for rec in self:
if not rec.logout_date:
raise ValidationError(
"%s is active. Only logged out session records can be "
"deleted" % rec.name)
return super().unlink()
def action_button_force_logout(self):
"""Logs out the user by clearing the session data."""
self.ensure_one()
self.update({'state': 'closed',
'status': 'blocked'})
state_mapped = self.env['user.session.login'].sudo().search(
[('user_id', '=', self.user_id.id)]).mapped('state')
if 'active' not in state_mapped:
self.sudo().user_id.status = 'blocked'
try:
self.update({'logout_date': fields.Datetime.now()})
path = odoo.tools.config.session_dir
store = sessions.FilesystemSessionStore(
path, session_class=odoo.http.OpenERPSession,
renew_missing=True)
session_fname = store.get_session_filename(self.sid)
sess_file = open(session_fname, 'rb')
sess = pickle.load(sess_file)
# updating the sess file
sess['login'] = None
sess['uid'] = None
sess['session_token'] = None
sess['context'] = {}
sess_file = open(session_fname, 'wb')
pickle.dump(sess, sess_file)
except FileNotFoundError:
self.update({'logout_date': fields.Datetime.now()})
def clear_records(self):
"""
Clears all the user session records that have a logout_date older
than the number of days specified in the settings.
"""
records = self.search([])
for rec in records:
if rec.logout_date and fields.Datetime.now() > rec.logout_date + \
timedelta(days=literal_eval(
self.env['ir.config_parameter'].sudo().get_param(
'user_session_management.records_retain_period')))\
and self.env['ir.config_parameter'].sudo().get_param(
'user_session_management.clear_log'):
rec.activity_ids.unlink()
rec.unlink()

7
user_session_management/security/ir.model.access.csv

@ -0,0 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_user_session_login_all,access.user.session.login.all,model_user_session_login,,0,1,1,0
access_user_session_login_user,access.user.session.login.user,model_user_session_login,user_session_management.user_session_management_group_user,1,1,1,0
access_user_session_login_manager,access.user.session.login.manager,model_user_session_login,user_session_management.user_session_management_group_manager,1,1,1,1
access_user_session_activity_all,access.user.session.activity.all,model_user_session_activity,,0,0,1,0
access_user_session_activity_user,access.user.session.activity.user,model_user_session_activity,user_session_management.user_session_management_group_user,1,0,1,0
access_user_session_activity_manager,access.user.session.activity.manager,model_user_session_activity,user_session_management.user_session_management_group_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_user_session_login_all access.user.session.login.all model_user_session_login 0 1 1 0
3 access_user_session_login_user access.user.session.login.user model_user_session_login user_session_management.user_session_management_group_user 1 1 1 0
4 access_user_session_login_manager access.user.session.login.manager model_user_session_login user_session_management.user_session_management_group_manager 1 1 1 1
5 access_user_session_activity_all access.user.session.activity.all model_user_session_activity 0 0 1 0
6 access_user_session_activity_user access.user.session.activity.user model_user_session_activity user_session_management.user_session_management_group_user 1 0 1 0
7 access_user_session_activity_manager access.user.session.activity.manager model_user_session_activity user_session_management.user_session_management_group_manager 1 1 1 1

18
user_session_management/security/user_session_management_groups.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Category-->
<record id="module_category_user_session_management"
model="ir.module.category">
<field name="name">User Session Management</field>
</record>
<!-- Groups-->
<record id="user_session_management_group_user" model="res.groups">
<field name="name">Session User</field>
<field name="category_id" ref="module_category_user_session_management"/>
</record>
<record id="user_session_management_group_manager" model="res.groups">
<field name="name">Session Manager</field>
<field name="category_id" ref="module_category_user_session_management"/>
<field name="implied_ids" eval="[(4, ref('user_session_management_group_user'))]"/>
</record>
</odoo>

39
user_session_management/security/user_session_management_security.xml

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Personal session rule-->
<record id="user_session_login_rule_personal_session" model="ir.rule">
<field name="name">Personal Session</field>
<field ref="model_user_session_login" name="model_id"/>
<field name="domain_force">
['|', ('user_id', '=', user.id), ('user_id', '=', False)]
</field>
<field name="groups"
eval="[(4, ref('user_session_management.user_session_management_group_user'))]"/>
</record>
<!-- All session rule-->
<record id="user_session_login_rule_all_session" model="ir.rule">
<field name="name">All Session</field>
<field ref="model_user_session_login" name="model_id"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups"
eval="[(4, ref('user_session_management.user_session_management_group_manager'))]"/>
</record>
<!-- Personal activity rule-->
<record id="user_session_activity_rule_personal_activity" model="ir.rule">
<field name="name">Personal Activity</field>
<field ref="model_user_session_activity" name="model_id"/>
<field name="domain_force">
['|', ('user_id', '=', user.id), ('user_id', '=', False)]
</field>
<field name="groups"
eval="[(4, ref('user_session_management.user_session_management_group_user'))]"/>
</record>
<!-- All activity rule-->
<record id="user_session_activity_rule_all_activity" model="ir.rule">
<field name="name">All Activity</field>
<field ref="model_user_session_activity" name="model_id"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups"
eval="[(4, ref('user_session_management.user_session_management_group_manager'))]"/>
</record>
</odoo>

BIN
user_session_management/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
user_session_management/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
user_session_management/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
user_session_management/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
user_session_management/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
user_session_management/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
user_session_management/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
user_session_management/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
user_session_management/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
user_session_management/static/description/assets/icons/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
user_session_management/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
user_session_management/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
user_session_management/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
user_session_management/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
user_session_management/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
user_session_management/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
user_session_management/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
user_session_management/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
user_session_management/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
user_session_management/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
user_session_management/static/description/assets/modules/budget_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
user_session_management/static/description/assets/modules/credit_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
user_session_management/static/description/assets/modules/employee_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
user_session_management/static/description/assets/modules/export_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
user_session_management/static/description/assets/modules/gantt_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
user_session_management/static/description/assets/modules/quotation_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
user_session_management/static/description/assets/screenshots/activities.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
user_session_management/static/description/assets/screenshots/conf_settings.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
user_session_management/static/description/assets/screenshots/hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
user_session_management/static/description/assets/screenshots/log_out.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
user_session_management/static/description/assets/screenshots/login.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
user_session_management/static/description/assets/screenshots/session_form.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
user_session_management/static/description/assets/screenshots/settings.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
user_session_management/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
user_session_management/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

623
user_session_management/static/description/index.html

@ -0,0 +1,623 @@
<div class="container" style="padding: 1rem !important; margin-bottom: 1rem !important;">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between"
style="border-bottom: 1px solid #d5d5d5;">
<div class="my-3">
<img src="./assets/icons/logo.png" style="width: auto !important; height: 40px !important;">
</div>
<div class="my-3 d-flex align-items-center">
<div
style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Community
</div>
<div style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
</div>
</div>
<div class="container" style="padding: 0rem 1.5rem 4rem !important">
<div class="row" style="height: 900px !important;">
<div class="col-sm-12 col-md-12 col-lg-12"
style="padding: 4rem 1rem !important; background-color: #714B67 !important; height: 600px !important; border-radius: 20px !important;">
<h1
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #FFFFFF !important; font-size: 3.5rem !important; text-align: center !important;">
Odoo User Session Management And Activity Tracking</h1>
<p
style="font-family: 'Montserrat', sans-serif !important; font-weight: 300 !important; color: #FFFFFF !important; font-size: 1.4rem !important; text-align: center !important;">
User Session and Activity Tracking
</p>
<img src="./assets/screenshots/hero.gif" class="img-responsive" width="100%" height="auto" />
</div>
</div>
<div class="row">
<div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin-bottom: 2rem !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-compass mr-2"></i>Explore this module
</h2>
</div>
<div class="col-md-6">
<a href="#overview" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Overview</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
Learn more about this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right" style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<a href="#features" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Features</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
View features of this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right" style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<a href="#screenshots" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Screenshots</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
See key screenshots of this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right" style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
</div>
<div class="row" id="overview">
<div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-pie-chart mr-2"></i>Overview
</h2>
</div>
<div class="col-mg-12 pl-3">
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important; line-height: 30px !important;">
This module will help you to monitor every user session and
activities during the session. It records the User, Login Date,
Logout Date, Device, OS, Browser, IP, Session ID and also the
activities during the session.<br>(Ensure the python
module 'user_agents' is installed in the system. Use the
terminal command <strong>'sudo pip3 install
user_agents'</strong> to install the module)</p>
</div>
</div>
<div class="row" id="features">
<div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-star mr-2"></i>Features
</h2>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Login Session History includes the Device, IP, OS, Browser details.</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Track the Read, Create, Update, and Delete operations in the selected model, done by the Internal users. </h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Managers can access all records, while users can access only their own records.</h4>
</div>
</div>
</div>
<div class="row" id="screenshots">
<div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-image mr-2"></i>Screenshots
</h2>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Configure the User Access Rights.</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
<strong>"Session user"</strong> has access to own documents only.
<strong>"Session Manager"</strong> has access to all documents.</p>
<img src="assets/screenshots/settings.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Configure the model to be tracked in the Configuration/Settings menu.</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Select the model to be tracked in here. Also, the Records Retain Period can be selected from here.</p>
<img src="assets/screenshots/conf_settings.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Login Details</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Then after re-log in you can see the login records are created.
</p>
<img src="assets/screenshots/login.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Activity Tracking</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
In the 'Activity' menu, all the activities are listed during the session.</p>
<img src="assets/screenshots/activities.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Session-Activity</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
The same data can be accessed from the form view of the corresponding Session
also.
</p>
<img src="assets/screenshots/session_form.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Logout Info</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
When the user logout the "Logout Date" will be recorded.</p>
<img src="assets/screenshots/log_out.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
</div>
<!-- SUGGESTED PRODUCTS -->
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center"
style="text-align: center; padding: 2.5rem 1rem !important;">
<h2 style="color: #212529 !important;">Suggested Products</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" />
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active" style="min-height:0px">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/export_stockinfo_xls/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/export_image.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/custom_gantt_view/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/gantt_image.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/sales_credit_limit/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/credit_image.png">
</div>
</a>
</div>
</div>
<div class="carousel-item" style="min-height:0px">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/base_account_budget/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/budget_image.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/product_to_quotation/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/quotation_image.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/employee_documents_expiry/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/employee_image.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="left:-25px;width: 35px;color: #000;"> <span class="carousel-control-prev-icon"><i
class="fa fa-chevron-left" style="font-size:24px"></i></span> </a> <a
class="carousel-control-next" href="#demo1" data-slide="next"
style="right:-25px;width: 35px;color: #000;">
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF SUGGESTED PRODUCTS -->
<!-- OUR SERVICES -->
<section class="container" style="margin-top: 6rem !important;">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Our Services</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" />
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</section>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<section class="container" style="margin-top: 6rem !important;">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Our Industries</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" />
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/trading-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/pos-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/education-black.png" class="img-responsive mb-3" height="48px"
width="48px">
<h5
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/manufacturing-black.png" class="img-responsive mb-3" height="48px"
width="48px">
<h5
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/ecom-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/service-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/restaurant-black.png" class="img-responsive mb-3" height="48px"
width="48px">
<h5
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/hotel-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</section>
<!-- END OF OUR INDUSTRIES -->
<!-- FOOTER -->
<!-- Footer Section -->
<section class="container" style="margin: 5rem auto 2rem;">
<div class="row" style="max-width:1540px;">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Need Help?</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" />
</div>
</div>
<!-- Contact Cards -->
<div class="row d-flex justify-content-center align-items-center"
style="max-width:1540px; margin: 0 auto 2rem auto;">
<div class="col-lg-12" style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; ">
<div class="row mt-4">
<div class="col-lg-6">
<a href="mailto:odoo@cybrosys.com" target="_blank" class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #4d4d4d; color: #FFF; border-radius: 4px;"><i
class="fa fa-envelope mr-2"></i>odoo@cybrosys.com</a>
</div>
<div class="col-lg-6">
<a href="https://api.whatsapp.com/send?phone=918606827707" target="_blank"
class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #25D366; color: #FFF; border-radius: 4px;"><i
class="fa fa-whatsapp mr-2"></i>+91 86068 27707</a>
</div>
</div>
</div>
</div>
<!-- End of Contact Cards -->
</section>
<!-- Footer -->
<section class="oe_container" style="padding: 2rem 3rem 1rem;">
<div class="row" style="max-width:1540px; margin: 0 auto; margin-right: 3rem; ">
<!-- Logo -->
<div class="col-lg-12 d-flex justify-content-center align-items-center" style="margin-top: 3rem;">
<img src="https://www.cybrosys.com/images/logo.png" width="200px" height="auto" />
</div>
<!-- End of Logo -->
<div class="col-lg-12">
<hr
style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;">
<!-- End of Footer Section -->
</div>
</div>
</section>
<!-- END OF FOOTER -->
</div>

89
user_session_management/views/res_config_settings_views.xml

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--Config_settings form view-->
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">
res.config.settings.view.form.inherit.user.session.management
</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('settings')]" position="inside">
<div class="app_settings_block" string="Sessions"
data-key="user_session_management">
<h2>User Activity Settings</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<div class="content-group">
<div class="mt16">
<label for="model_ids"/>
<field name="model_ids"
widget="many2many_tags"/>
<div class="text-muted">
Add the models to track.
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<div class="content-group">
<div class="mt16">
<field name="clear_log"/>
</div>
</div>
</div>
<div class="o_setting_right_pane">
<div class="content-group">
<div class="mt16">
<label for="clear_log"/>
</div>
</div>
</div>
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<div class="content-group"
attrs="{'invisible':[('clear_log','=',False)]}">
<div class="mt16">
<label for="records_retain_period"/>
<field name="records_retain_period"
type="number"
style="width:10%"/>
<span>day(s)</span>
<div class="text-muted">
Number of days after a session ends
before its logs will be
automatically removed from the
system.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
<!--Action-->
<record id="res_config_settings_action_view_form"
model="ir.actions.act_window">
<field name="name">User Session Management Settings</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.config.settings</field>
<field name="view_mode">form</field>
<field name="target">inline</field>
<field name="context">{'module': 'user_session_management'}</field>
</record>
<!--Menus -->
<menuitem id="res_config_settings_menu" name="Configuration"
parent="user_session_management.user_session_login_menu"/>
<menuitem id="res_config_settings_menu_action"
name="Settings"
parent="res_config_settings_menu"
groups="user_session_management.user_session_management_group_manager"
action="user_session_management.res_config_settings_action_view_form"/>
</odoo>

16
user_session_management/views/res_users_views.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--Res users tree inherit-->
<record id="view_users_form" model="ir.ui.view">
<field name="name">res.users.view.form.inherit.user.session.management
</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='name']" position="before">
<field name="status" widget="state_selection"
style="margin-right:24px;"/>
</xpath>
</field>
</record>
</odoo>

92
user_session_management/views/user_session_activity_views.xml

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Session activity tree view -->
<record id="user_session_activity_view_tree" model="ir.ui.view">
<field name="name">user.session.activity.view.tree</field>
<field name="model">user.session.activity</field>
<field name="arch" type="xml">
<tree name="session_activity_tree" create="0">
<field name="login_id"/>
<field name="name"/>
<field name="user_id"/>
<field name="performed_date"/>
<field name="model"/>
<field name="action"/>
</tree>
</field>
</record>
<!--Session activity form view -->
<record id="user_session_activity_view_form" model="ir.ui.view">
<field name="name">user.session.activity.view.form</field>
<field name="model">user.session.activity</field>
<field name="arch" type="xml">
<form name="session_activity_form" create="0" edit="0">
<sheet>
<group>
<group name="session_activity_gp_1">
<field name="name"/>
<field name="user_id"/>
<field name="model"/>
<field name="record"
attrs="{'invisible': [('record', '=', 0)]}"/>
<field name="records"
attrs="{'invisible': [('records', '=', '')]}"/>
<field name="login_id"/>
</group>
<group name="session_activity_gp_2">
<field name="action"/>
<field name="performed_date"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!--Search view -->
<record id="user_session_activity_view_search" model="ir.ui.view">
<field name="name">user.session.activity.view.search</field>
<field name="model">user.session.activity</field>
<field name="arch" type="xml">
<search string="Search User activity">
<field name="name"/>
<field name="model"/>
<field name="action"/>
<field name="user_id"/>
<filter string="Only Read" name="read"
domain="[('action','=','read')]"/>
<filter string="Only Create" name="create"
domain="[('action','=','create')]"/>
<filter string="Only Modify" name="modify"
domain="[('action','=','modify')]"/>
<filter string="Only Delete" name="delete"
domain="[('action','=','delete')]"/>
<separator/>
<filter string="Performed Date" name="performed_date"
date="performed_date"/>
<filter string="Model" name="group_by_model" domain="[]"
context="{'group_by': 'model'}"/>
<filter string="Performed Action" name="group_by_action"
domain="[]" context="{'group_by': 'action'}"/>
<filter string="User" name="group_by_user" domain="[]"
context="{'group_by': 'user_id'}"/>
<filter string="Session" name="group_by_session" domain="[]"
context="{'group_by': 'login_id'}"/>
<filter string="Performed Date" name="group_by_date" domain="[]"
context="{'group_by': 'performed_date'}"/>
</search>
</field>
</record>
<!--Action -->
<record id="user_session_activity_action"
model="ir.actions.act_window">
<field name="name">Activity Log</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">user.session.activity</field>
<field name="view_mode">tree,form</field>
</record>
<!--Menus -->
<menuitem name="Activity" id="user_session_activity_menu_action"
parent="user_session_login_menu"
action="user_session_activity_action"/>
</odoo>

98
user_session_management/views/user_session_login_views.xml

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Session login tree view -->
<record id="user_session_login_view_tree" model="ir.ui.view">
<field name="name">use.session.login.view.tree</field>
<field name="model">user.session.login</field>
<field name="arch" type="xml">
<tree name="session_login_tree" create="0">
<field name="status" widget="state_selection" nolabel="1"
colspan="1"/>
<field name="name"/>
<field name="user_id"/>
<field name="login_date"/>
<field name="logout_date"/>
<field name="session_duration"
attrs="{'invisible': [('logout_date', '=', False)]}"/>
<field name="device"/>
<field name="os"/>
<field name="browser"/>
<field name="state"/>
<button name="action_button_force_logout" type="object"
icon="fa-sign-out"
attrs="{'invisible': [('state', '=', 'closed')]}"/>
</tree>
</field>
</record>
<!--Session login form view-->
<record id="user_session_login_view_form" model="ir.ui.view">
<field name="name">user.session.login.view.form</field>
<field name="model">user.session.login</field>
<field name="arch" type="xml">
<form name="session_login_form" create="0" edit="0">
<header>
<field name="state" widget="statusbar"/>
</header>
<sheet>
<h3>
<field name="status" widget="state_selection"
style="margin-right:24px;"/>
<field name="name"/>
</h3>
<group>
<group name="gp_session_left">
<field name="user_id"/>
<field name="login_date"/>
<field name="logout_date"/>
<field name="session_duration"
attrs="{'invisible': [('logout_date', '=', False)]}"/>
</group>
<group name="gp_session_right">
<field name="device"/>
<field name="os"/>
<field name="browser"/>
<field name="ip_address"/>
<field name="sid" invisible="1"/>
</group>
</group>
<notebook name="session-activities">
<page name="session-activities" string="Activities">
<field name="activity_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!--Search view -->
<record id="user_session_login_view_search" model="ir.ui.view">
<field name="name">user.session.login.view.search</field>
<field name="model">user.session.login</field>
<field name="arch" type="xml">
<search string="Search User Session">
<field name="name"/>
<field name="user_id"/>
<filter string="Active" name="active"
domain="[('state','=','active')]"/>
<filter string="Closed" name="closed"
domain="[('state','=','closed')]"/>
<separator/>
<filter string="Date" name="login_date"
date="login_date"/>
</search>
</field>
</record>
<!--Action -->
<record id="user_session_login_action" model="ir.actions.act_window">
<field name="name">Sessions</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">user.session.login</field>
<field name="view_mode">tree,form</field>
</record>
<!--Menus -->
<menuitem name="Sessions" id="user_session_login_menu"
web_icon="user_session_management,static/description/icon.png"/>
<menuitem id="user_session_login_menu_action"
parent="user_session_login_menu"
action="user_session_login_action"/>
</odoo>
Loading…
Cancel
Save