Browse Source

May 30: [ADD] Initial Commit 'restrict_logins'

pull/254/merge
RisvanaCybro 11 months ago
parent
commit
879c98d8a6
  1. 49
      restrict_logins/README.rst
  2. 23
      restrict_logins/__init__.py
  3. 46
      restrict_logins/__manifest__.py
  4. 22
      restrict_logins/controllers/__init__.py
  5. 155
      restrict_logins/controllers/restrict_logins.py
  6. 17
      restrict_logins/data/ir_cron_data.xml
  7. 5
      restrict_logins/doc/RELEASE_NOTES.md
  8. 23
      restrict_logins/models/__init__.py
  9. 106
      restrict_logins/models/ir_http.py
  10. 123
      restrict_logins/models/res_users.py
  11. BIN
      restrict_logins/static/description/assets/icons/check.png
  12. BIN
      restrict_logins/static/description/assets/icons/chevron.png
  13. BIN
      restrict_logins/static/description/assets/icons/cogs.png
  14. BIN
      restrict_logins/static/description/assets/icons/consultation.png
  15. BIN
      restrict_logins/static/description/assets/icons/ecom-black.png
  16. BIN
      restrict_logins/static/description/assets/icons/education-black.png
  17. BIN
      restrict_logins/static/description/assets/icons/hotel-black.png
  18. BIN
      restrict_logins/static/description/assets/icons/license.png
  19. BIN
      restrict_logins/static/description/assets/icons/lifebuoy.png
  20. BIN
      restrict_logins/static/description/assets/icons/logo.png
  21. BIN
      restrict_logins/static/description/assets/icons/manufacturing-black.png
  22. BIN
      restrict_logins/static/description/assets/icons/pos-black.png
  23. BIN
      restrict_logins/static/description/assets/icons/puzzle.png
  24. BIN
      restrict_logins/static/description/assets/icons/restaurant-black.png
  25. BIN
      restrict_logins/static/description/assets/icons/service-black.png
  26. BIN
      restrict_logins/static/description/assets/icons/trading-black.png
  27. BIN
      restrict_logins/static/description/assets/icons/training.png
  28. BIN
      restrict_logins/static/description/assets/icons/update.png
  29. BIN
      restrict_logins/static/description/assets/icons/user.png
  30. BIN
      restrict_logins/static/description/assets/icons/wrench.png
  31. BIN
      restrict_logins/static/description/assets/misc/categories.png
  32. BIN
      restrict_logins/static/description/assets/misc/check-box.png
  33. BIN
      restrict_logins/static/description/assets/misc/compass.png
  34. BIN
      restrict_logins/static/description/assets/misc/corporate.png
  35. BIN
      restrict_logins/static/description/assets/misc/customer-support.png
  36. BIN
      restrict_logins/static/description/assets/misc/cybrosys-logo.png
  37. BIN
      restrict_logins/static/description/assets/misc/features.png
  38. BIN
      restrict_logins/static/description/assets/misc/logo.png
  39. BIN
      restrict_logins/static/description/assets/misc/pictures.png
  40. BIN
      restrict_logins/static/description/assets/misc/pie-chart.png
  41. BIN
      restrict_logins/static/description/assets/misc/right-arrow.png
  42. BIN
      restrict_logins/static/description/assets/misc/star.png
  43. BIN
      restrict_logins/static/description/assets/misc/support.png
  44. BIN
      restrict_logins/static/description/assets/misc/whatsapp.png
  45. BIN
      restrict_logins/static/description/assets/modules/customer_product_qrcode.png
  46. BIN
      restrict_logins/static/description/assets/modules/customized_barcode_generator.png
  47. BIN
      restrict_logins/static/description/assets/modules/employee_dynamic_fields.png
  48. BIN
      restrict_logins/static/description/assets/modules/list_view_sticky_header.png
  49. BIN
      restrict_logins/static/description/assets/modules/odoo_website_helpdesk.png
  50. BIN
      restrict_logins/static/description/assets/modules/todo_list.png
  51. BIN
      restrict_logins/static/description/assets/screenshots/1.png
  52. BIN
      restrict_logins/static/description/assets/screenshots/2.png
  53. BIN
      restrict_logins/static/description/assets/screenshots/3.png
  54. BIN
      restrict_logins/static/description/assets/screenshots/hero.gif
  55. BIN
      restrict_logins/static/description/banner.png
  56. BIN
      restrict_logins/static/description/icon.png
  57. 583
      restrict_logins/static/description/index.html
  58. 15
      restrict_logins/views/login_clear_session_template.xml
  59. 25
      restrict_logins/views/res_users_views.xml

49
restrict_logins/README.rst

@ -0,0 +1,49 @@
.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
Restrict Concurrent User Login
==============================
This module ensures restricted concurrent sessions, enforces user force logout, and automates session expiry for enhanced security and user management.
Configuration
=============
No additional configurations needed.
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
License
-------
Lesser General Public License, Version 3 (LGPL v3)
(https://www.gnu.org/licenses/lgpl-3.0-standalone.html)
Credits
-------
* Developers : (V13) Milind Mohan,
(V14) Aysha Shalin,
(V15) Aysha Shalin
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
restrict_logins/__init__.py

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

46
restrict_logins/__manifest__.py

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Technologies (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
{
'name': 'Restrict Concurrent User Login',
'version': '15.0.1.0.0',
'category': 'Extra Tools',
'summary': """Ensures restricted concurrent sessions, enforces user force
logout, and automates session expiry for enhanced security.""",
'description': """This module ensures security by restricting concurrent
user sessions and provides the option for forced logout. It includes
automatic session expiry after a set duration, managing user logins
efficiently.""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com',
'data': [
'data/ir_cron_data.xml',
'views/res_users_views.xml',
'views/login_clear_session_template.xml',
],
'images': ['static/description/banner.png'],
'license': 'LGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

22
restrict_logins/controllers/__init__.py

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

155
restrict_logins/controllers/restrict_logins.py

@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Technologies (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
import os
import werkzeug
import werkzeug.exceptions
import werkzeug.routing
from odoo.addons.web.controllers import main
import odoo
import odoo.modules.registry
from odoo import SUPERUSER_ID
from odoo import http
from odoo.http import request
from odoo.tools._vendor import sessions
from odoo.tools.translate import _
def clear_session_history(u_sid, f_uid=False):
""" Clear all the user session histories of a particular user """
path = odoo.tools.config.session_dir
store = sessions.FilesystemSessionStore(
path, session_class=odoo.http.OpenERPSession, renew_missing=True)
session_fname = store.get_session_filename(u_sid)
try:
os.remove(session_fname)
return True
except OSError:
pass
return False
def super_clear_all():
""" Clear all the user session histories """
path = odoo.tools.config.session_dir
store = sessions.FilesystemSessionStore(
path, session_class=odoo.http.OpenERPSession, renew_missing=True)
for fname in os.listdir(store.path):
path = os.path.join(store.path, fname)
try:
os.unlink(path)
except OSError:
pass
return True
class Session(main.Session):
"""
This class includes methods to handle user logouts, clear individual user
sessions, and perform a force logout, which logs out from all devices.
"""
@http.route('/web/session/logout', type='http', auth="none")
def logout(self, redirect='/web'):
""" Logs out the current user by clearing their session. """
user = request.env['res.users'].with_user(1).search(
[('id', '=', request.session.uid)])
user._clear_session() # Clear user session
request.session.logout(keep_db=True)
return werkzeug.utils.redirect(redirect, 303)
@http.route('/clear_all_sessions', type='http', auth="none")
def logout_all(self, redirect='/web', f_uid=False):
""" Log out from all the sessions of the current user """
if f_uid:
user = request.env['res.users'].with_user(1).browse(int(f_uid))
if user:
# Clear session file for the user
session_cleared = clear_session_history(user.sid, f_uid)
if session_cleared:
user._clear_session() # Clear user session
request.session.logout(keep_db=True)
return werkzeug.utils.redirect(redirect, 303)
@http.route('/super/logout_all', type='http', auth="none")
def super_logout_all(self, redirect='/web'):
""" Log out from all the sessions of all users. """
users = request.env['res.users'].with_user(1).search([])
for user in users:
# Clear session file for the user
session_cleared = super_clear_all()
if session_cleared:
user._clear_session() # Clear user session
request.session.logout(keep_db=True)
return werkzeug.utils.redirect(redirect, 303)
class Home(main.Home):
""" This class includes methods related to user authentication and login."""
@http.route('/web/login', type='http', auth="none")
def web_login(self, redirect=None, **kw):
""" Handle user login through the web interface. """
main.ensure_db()
request.params['login_success'] = False
if (request.httprequest.method == 'GET' and redirect and
request.session.uid):
return request.redirect(redirect)
if not request.uid:
request.uid = odoo.SUPERUSER_ID
values = request.params.copy()
try:
values['databases'] = http.db_list()
except odoo.exceptions.AccessDenied:
values['databases'] = None
if request.httprequest.method == 'POST':
old_uid = request.uid
try:
uid = request.session.authenticate(request.session.db,
request.params['login'],
request.params['password'])
request.params['login_success'] = True
return request.redirect(
self._login_redirect(uid, redirect=redirect))
except odoo.exceptions.AccessDenied as e:
failed_uid = request.uid
request.uid = old_uid
if e.args == odoo.exceptions.AccessDenied().args:
values['error'] = _("Wrong login/password")
elif e.args[0] == "already_logged_in":
values['error'] = "User already logged in. Log out from " \
"other devices and try again."
values['logout_all'] = True
values[
'failed_uid'] = failed_uid if (
failed_uid != SUPERUSER_ID) else False
else:
values['error'] = e.args[0]
else:
if 'error' in request.params and request.params.get(
'error') == 'access':
values['error'] = _('Only employee can access this database. '
'Please contact the administrator.')
if 'login' not in values and request.session.get('auth_login'):
values['login'] = request.session.get('auth_login')
if not odoo.tools.config['list_db']:
values['disable_database_manager'] = True
response = request.render('web.login', values)
response.headers['X-Frame-Options'] = 'DENY'
return response

17
restrict_logins/data/ir_cron_data.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Scheduled action to validate user sessions. -->
<data>
<record model="ir.cron" id="validate_user_sessions">
<field name="name">User: Validate User Sessions</field>
<field name="model_id" ref="model_res_users"/>
<field name="state">code</field>
<field name="code">model._validate_sessions()</field>
<field name="interval_number">1</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
<field name="active" eval="True"/>
</record>
</data>
</odoo>

5
restrict_logins/doc/RELEASE_NOTES.md

@ -0,0 +1,5 @@
## Module <restrict_logins>
#### 19.03.2024
#### Version 15.0.1.0.0
##### ADD
- Initial Commit for Restrict Concurrent User Login

23
restrict_logins/models/__init__.py

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

106
restrict_logins/models/ir_http.py

@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Technologies (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
import logging
from datetime import datetime, timedelta
import werkzeug
import werkzeug.exceptions
import werkzeug.routing
from odoo import http, models, SUPERUSER_ID
from odoo.exceptions import AccessDenied
from odoo.http import request
_logger = logging.getLogger(__name__)
class IrHttp(models.AbstractModel):
""" Extends the Odoo abstract model 'ir.http' for custom HTTP handling."""
_inherit = 'ir.http'
@classmethod
def _authenticate(cls, endpoint):
""" This method updates user session details, checks for session
mismatches and performs necessary updates."""
auth_method = endpoint.routing["auth"]
if request._is_cors_preflight(endpoint):
auth_method = 'none'
try:
if request.session.uid:
uid = request.session.uid
user_pool = request.env['res.users'].with_user(
SUPERUSER_ID).browse(uid)
def _update_user(u_sid, u_now, u_exp_date, u_uid):
""" Function for updating session details for the
corresponding user."""
if u_uid and u_exp_date and u_sid and u_now:
query = """update res_users set sid = '%s',
last_update = '%s',exp_date = '%s',
logged_in = 'TRUE' where id = %s
""" % (u_sid, u_now, u_exp_date, u_uid)
request.env.cr.execute(query)
sid = request.session.sid
last_update = user_pool.last_update
now = datetime.now()
exp_date = datetime.now() + timedelta(minutes=45)
# Check that the authentication contains bus_inactivity
request_params = request.params.copy()
if 'options' in request_params and 'bus_inactivity' in \
request_params['options']:
# Update session if there is sid mismatch
if uid and user_pool.sid and sid != user_pool.sid:
_update_user(sid, now, exp_date, uid)
else:
# Update if there is no session data and user is active
if not user_pool.last_update and not user_pool.sid and \
not user_pool.logged_in:
_update_user(sid, now, exp_date, uid)
# Update sid and date if last update is above 0.5 min
if last_update:
update_diff = (datetime.now() -
last_update).total_seconds() / 60.0
if uid and (update_diff > 0.5 or sid != user_pool.sid):
_update_user(sid, now, exp_date, uid)
except Exception as e:
_logger.info(
"Exception during updating user session...%s", e)
pass
try:
if request.session.uid:
try:
request.session.check_security()
# What if error in security.check()
# -> res_users.check()
# -> res_users._check_credentials()
except (AccessDenied, http.SessionExpiredException):
# All other exceptions mean undetermined status
# (e.g.connection pool full), let them bubble up
request.session.logout(keep_db=True)
if request.uid is None:
getattr(cls, "_auth_method_%s" % auth_method)()
except (AccessDenied, http.SessionExpiredException,
werkzeug.exceptions.HTTPException):
raise
except Exception:
_logger.info("Exception during request Authentication.",
exc_info=True)
raise AccessDenied()
return auth_method

123
restrict_logins/models/res_users.py

@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Technologies (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import logging
from datetime import datetime, timedelta
import pytz
from odoo import SUPERUSER_ID
from odoo import api, fields, models
from odoo.exceptions import AccessDenied
from odoo.http import request
from ..controllers.restrict_logins import clear_session_history
_logger = logging.getLogger(__name__)
class ResUsers(models.Model):
""" Inheriting 'res.users' for adding fields related session."""
_inherit = 'res.users'
sid = fields.Char(string='Session ID', help="ID of session")
exp_date = fields.Datetime(string='Current Session Expiration',
help="Time of expiring of current session")
logged_in = fields.Boolean(string='Logged In',
help="User is currently logged in")
last_update = fields.Datetime(string="Last Connection",
help="Last log in")
@classmethod
def _login(cls, db, login, password, user_agent_env):
"""
Handles user login authentication.
Notify user if they are already logged in and attempt to log in from
other device.
"""
if not password:
raise AccessDenied()
ip = request.httprequest.environ['REMOTE_ADDR'] if request else 'n/a'
try:
with cls.pool.cursor() as cr:
self = api.Environment(cr, SUPERUSER_ID, {})[cls._name]
with self._assert_can_auth():
user = self.search(self._get_login_domain(login),
order=self._get_login_order(), limit=1)
if not user:
raise AccessDenied()
user = user.with_user(user)
user._check_credentials(password, user_agent_env)
tz = request.httprequest.cookies.get(
'tz') if request else None
if tz in pytz.all_timezones and (
not user.tz or not user.login_date):
user.tz = tz
# Check sid and exp date
if user.exp_date and user.sid and user.logged_in:
_logger.warning("User %s is already logged in "
"into the system!. Multiple "
"sessions are not allowed for "
"security reasons!" % user.name)
request.uid = user.id
raise AccessDenied("already_logged_in")
# Save user session detail if login is successful
user._save_session()
user._update_last_login()
except AccessDenied:
_logger.info("Login failed for db:%s login:%s from %s", db, login,
ip)
raise
_logger.info("Login successful for db:%s login:%s from %s", db, login,
ip)
return user.id
def _clear_session(self):
""" Function for clearing the session details of user."""
self.write({
'sid': False,
'exp_date': False,
'logged_in': False,
'last_update': datetime.now()
})
def _save_session(self):
""" Function for saving session details of the corresponding user."""
exp_date = datetime.utcnow() + timedelta(minutes=45)
sid = request.httprequest.session.sid
self.with_user(SUPERUSER_ID).write({
'sid': sid,
'exp_date': exp_date,
'logged_in': True,
'last_update': datetime.now()
})
def _validate_sessions(self):
""" Function for validating user sessions."""
users = self.search([('exp_date', '!=', False)])
for user in users:
if user.exp_date < datetime.utcnow():
# Clear session file for the user
session_cleared = clear_session_history(user.sid)
if session_cleared:
user._clear_session() # Clear user session
_logger.info("Cron _validate_session: "
"cleared session user: %s" % (user.name))
else:
_logger.info("Cron _validate_session: failed to "
"clear session user: %s" % (user.name))

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
restrict_logins/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
restrict_logins/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
restrict_logins/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
restrict_logins/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
restrict_logins/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
restrict_logins/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
restrict_logins/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
restrict_logins/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
restrict_logins/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
restrict_logins/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
restrict_logins/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
restrict_logins/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
restrict_logins/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
restrict_logins/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
restrict_logins/static/description/assets/modules/customer_product_qrcode.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
restrict_logins/static/description/assets/modules/customized_barcode_generator.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
restrict_logins/static/description/assets/modules/employee_dynamic_fields.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
restrict_logins/static/description/assets/modules/list_view_sticky_header.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
restrict_logins/static/description/assets/modules/odoo_website_helpdesk.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
restrict_logins/static/description/assets/modules/todo_list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
restrict_logins/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

BIN
restrict_logins/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
restrict_logins/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

BIN
restrict_logins/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
restrict_logins/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

583
restrict_logins/static/description/index.html

@ -0,0 +1,583 @@
<div class="container" style="background-color: #714B67; min-height: 600px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="info"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="./assets/misc/cybrosys-logo.png" width="42" height="42"
style="width: 42px; height: 42px;"/>
<div class="my-3">
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
<div style="color: #017E84; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Odoo.sh
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<!-- APP HERO -->
<div class="app-hero">
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Restrict Concurrent User Login</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">
Restrict Concurrent Sessions for Users</p>
<!-- END OF APP HERO -->
<img src="./assets/screenshots/hero.gif"
style="width: 75%; height: auto; position: absolute; margin-left: auto; margin-right: auto; top: 45%; left: 12%; right: auto;"/>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Explore This Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn more about this module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View features of this module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View screenshots for this module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Overview
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
This module is designed to enhance security by restricting users from having
multiple concurrent logins. If a user is already logged in on one device,
they will be prevented from logging in on another. Additionally, the module
offers the capability to force logout for users. Inactive sessions will
automatically expire after 45 minutes, further enhancing security measures.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Features
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Restrict Concurrent Sessions for Users</span>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;
position:absolute; left: 58px; bottom: 123px;">
Restrict Concurrent Sessions to enhance security.</p>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Force User Logout</span>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;
position:absolute; left: 58px; bottom: 52px;">
Option to log out from all logged in devices.</p>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Automatic Session Expiration</span>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;
position:absolute; left: 58px; bottom: -10px;">
Automatic Session Expiration After 45 Minutes.</p>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Log in to Odoo</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
After installation, Log in to Odoo.</p>
<img src="assets/screenshots/1.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Alert When the User is Logged in from Additional Devices.</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
When attempting to Log in, a notification will appear if the user is already logged in.</p>
<img src="assets/screenshots/2.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Option for Forced Logout.</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Enable the ability to force logout from devices that are already logged in.</p>
<img src="assets/screenshots/3.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="./assets/misc/categories.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Related Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<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/odoo_website_helpdesk/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/odoo_website_helpdesk.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/todo_list/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/todo_list.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/list_view_sticky_header/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/list_view_sticky_header.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active"
style="min-height: 198.656px;">
<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/customer_product_qrcode/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/customer_product_qrcode.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/customized_barcode_generator/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/customized_barcode_generator.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_dynamic_fields/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/employee_dynamic_fields.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="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="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 RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="./assets/misc/star.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<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>
</div>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="./assets/misc/corporate.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; 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: 0px; 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: 0px; 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: 0px; 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: 0px; 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: 0px; 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: 0px; 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: 0px; 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>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="./assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="./assets/misc/support.png" height="48" width="48"
style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help?
Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="./assets/misc/whatsapp.png" height="52" width="52"
style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
+91 86068 27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="./assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>
<!-- END OF SUPPORT -->

15
restrict_logins/views/login_clear_session_template.xml

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Extends the template to display a link for users to log out from other devices positioned after an alert message in the 'web.login' template. -->
<template id="login_clear_session" name="Clear User Sessions" inherit_id="web.login">
<xpath expr="//p[hasclass('alert-danger')]" position="after">
<t t-if="logout_all">
<div class="justify-content-between mt-2 d-flex small">
<a style="margin-left: auto; margin-right: auto;" t-att-href="'/clear_all_sessions?f_uid='+str(failed_uid)">
Logout from other devices.
</a>
</div>
</t>
</xpath>
</template>
</odoo>

25
restrict_logins/views/res_users_views.xml

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Adding fields related to session in 'res.users' tree view. -->
<record id="view_users_tree" model="ir.ui.view">
<field name="name">res.users.view.tree.inherit.restrict.logins</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='login_date']" position="attributes">
<attribute name="string">Last Login</attribute>
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='login_date']" position="after">
<field name="last_update" readonly="1"/>
</xpath>
<xpath expr="//field[@name='login_date']" position="before">
<field name="logged_in" string="Logged In" readonly="1"/>
<field name="exp_date" readonly="1"/>
</xpath>
</field>
</record>
</odoo>
Loading…
Cancel
Save