@ -0,0 +1,41 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Anjhana A K (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 http |
|||
from odoo.http import Controller, request |
|||
|
|||
|
|||
class LoginController(Controller): |
|||
"""Controller that works when Login With QR clicked""" |
|||
|
|||
@http.route(['/web/redirect'], type='json', auth='none', website=True, |
|||
csrf=False, csrf_token=None) |
|||
def scanner(self, scanned_qr): |
|||
"""This code scans the QR provided and Login to the corresponding user |
|||
note: Only Internal User can log in through it""" |
|||
users = request.env['res.users'].sudo().search([('share', '=', False)]) |
|||
login = users.mapped('login') |
|||
if scanned_qr in login: |
|||
request.session.authenticate_without_passwd( |
|||
request.session.db, scanned_qr) |
|||
return request.redirect('/') |
|||
else: |
|||
return False |
@ -1,68 +0,0 @@ |
|||
import cv2 |
|||
from pyzbar.pyzbar import decode |
|||
from odoo.http import Controller, request |
|||
from odoo import http |
|||
|
|||
SIGN_UP_REQUEST_PARAMS = {'db', 'login', 'debug', 'token', 'message', 'error', |
|||
'scope', 'mode', |
|||
'redirect', 'redirect_hostname', 'email', 'name', |
|||
'partner_id', |
|||
'password', 'confirm_password', 'city', 'country_id', |
|||
'lang', 'signup_email'} |
|||
|
|||
|
|||
class LoginController(Controller): |
|||
"""controller that works when Login With QR clicked""" |
|||
|
|||
@http.route(['/web/redirect'], type='http', auth='none', website=True, |
|||
csrf=False, csrf_token=None) |
|||
def open_scanner(self, *args, **kw): |
|||
"""This code scan the QR provided and Login to the corresponding user |
|||
note: Only Internal User can login through it""" |
|||
try: |
|||
cap = cv2.VideoCapture(0) |
|||
cap.set(3, 640) |
|||
cap.set(4, 480) |
|||
|
|||
while True: |
|||
ret, frame = cap.read() |
|||
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) |
|||
for qr_code in decode(gray): |
|||
(x, y, w, h) = qr_code.rect |
|||
cv2.rectangle(frame, (x, y), (x + w, y + h), |
|||
(0, 255, 0), 2) |
|||
decoded_text = qr_code.data.decode("utf-8") |
|||
users = request.env['res.users'].search( |
|||
[('share', '=', False)]) |
|||
login = users.mapped('login') |
|||
if decoded_text in login: |
|||
request.session.authenticate_without_passwd( |
|||
request.session.db, decoded_text) |
|||
cap.release() |
|||
cv2.destroyAllWindows() |
|||
return request.redirect('/') |
|||
else: |
|||
cap.release() |
|||
cv2.destroyAllWindows() |
|||
# Use the overridden web_login method to show error message |
|||
values = {k: v for k, v in request.params.items() if |
|||
k in SIGN_UP_REQUEST_PARAMS} |
|||
|
|||
values['error'] = ("Wrong QR Code") |
|||
request.update_env(user=request.session.uid) |
|||
request.env["ir.http"]._auth_method_public() |
|||
response = request.render('web.login', values) |
|||
|
|||
return response |
|||
|
|||
# Display the resulting frame |
|||
cv2.imshow('scanner- to exit press "q"', frame) |
|||
code = cv2.waitKey(1) |
|||
|
|||
if code == ord('q'): |
|||
cap.release() |
|||
cv2.destroyAllWindows() |
|||
return request.redirect('/web/login') |
|||
except Exception: |
|||
return request.render("login_using_qr.be_patient") |
|||
|
@ -1,7 +1,6 @@ |
|||
## Module <login_using_qr> |
|||
|
|||
#### 29.07.2023 |
|||
#### Version 16.0.1.0.0 |
|||
#### 09.02.2024 |
|||
#### Version 17.0.1.0.0 |
|||
#### ADD |
|||
|
|||
- Initial commit for Login using QR Code |
|||
- Initial commit for Login using Qr code |
|||
|
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 284 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 357 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 199 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 343 KiB |
After Width: | Height: | Size: 536 KiB |
After Width: | Height: | Size: 374 KiB |
After Width: | Height: | Size: 339 KiB |
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 6.8 KiB |
@ -0,0 +1,34 @@ |
|||
.clearfix.oe_login_buttons.text-center.mb-1.pt-3{ |
|||
position:relative; |
|||
} |
|||
|
|||
.qr_video { |
|||
position: absolute; |
|||
top: -353px; |
|||
left: -269px; |
|||
} |
|||
|
|||
.video-container{ |
|||
width:717px; |
|||
} |
|||
|
|||
.video-container video{ |
|||
width:100% !important; |
|||
height:100% !important; |
|||
} |
|||
|
|||
.o_database_list .input-group-prepend .btn, .input-group-append a{ |
|||
z-index:0 !important; |
|||
} |
|||
|
|||
@media (max-width: 767.98px) { |
|||
.qr_video{ |
|||
position: absolute; |
|||
top: -281px; |
|||
min-width: 200px; |
|||
left: -63px; |
|||
} |
|||
.video-container { |
|||
width:360px; |
|||
|
|||
}} |
@ -0,0 +1,54 @@ |
|||
/** @odoo-module **/ |
|||
import rpc from 'web.rpc'; |
|||
var publicWidget = require('web.public.widget'); |
|||
var ajax = require('web.ajax'); |
|||
publicWidget.registry.QrLogin = publicWidget.Widget.extend({ |
|||
selector: '.oe_qr_login', |
|||
events: { |
|||
'click #login_click': '_onLoginClick', |
|||
'click #close_qr_scanner':'_onClickClose' |
|||
}, |
|||
|
|||
_onClickClose: function(ev) { |
|||
window.location.reload(); |
|||
}, |
|||
|
|||
async _onLoginClick(ev) { |
|||
ev.target.offsetParent.querySelector('.close_button').classList.remove('d-none'); |
|||
const video = ev.target.offsetParent.querySelector('#video'); |
|||
var cam_stream = await navigator.mediaDevices.getUserMedia({ video: true}); |
|||
video.srcObject = cam_stream; |
|||
video.addEventListener('loadedmetadata', (event) => { |
|||
// Adjust video size once metadata is loaded
|
|||
video.width = video.videoWidth; |
|||
video.height = video.videoHeight; |
|||
}); |
|||
video.addEventListener('canplay', () => { |
|||
const canvas = document.createElement('canvas'); |
|||
const context = canvas.getContext('2d'); |
|||
canvas.width = video.width; |
|||
canvas.height = video.height; |
|||
setInterval(() => { |
|||
context.drawImage(video, 0, 0, canvas.width, canvas.height); |
|||
const imageData = context.getImageData(0, 0, canvas.width, canvas.height); |
|||
const code = jsQR(imageData.data, imageData.width, imageData.height); |
|||
if (code) { |
|||
ajax.jsonRpc('/web/redirect', 'call', {'scanned_qr': code.data} |
|||
).then((token) => { |
|||
if(token){ |
|||
cam_stream.getTracks().forEach(function(track) { |
|||
track.stop(); |
|||
window.location.href = '/'; |
|||
}); |
|||
} |
|||
else{ |
|||
alert('Scanned QR does not exist. Please try again.'); |
|||
window.location.reload(); |
|||
} |
|||
}); |
|||
} |
|||
}, 1000); // Adjust the interval as needed
|
|||
}); |
|||
} |
|||
|
|||
}) |
@ -1,11 +1,24 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!--calling the controller of scanner from login page--> |
|||
<!--Calling the controller of scanner from login page--> |
|||
<template id="qr_login" inherit_id="web.login" name="QR scanner"> |
|||
<xpath expr="//button[hasclass('btn-primary')]" position="after"> |
|||
<div class="justify-content-between mt-2 d-flex small"> |
|||
<a href="/web/redirect">Login With QR</a> |
|||
<xpath expr="//div[hasclass('o_login_auth')]" position="before"> |
|||
<div class="justify-content-between mt-2 d-flex small oe_qr_login"> |
|||
<a href="#" id="login_click" t-on-click='_onLoginClick'>Login With QR</a> |
|||
<div class="qr_video"> |
|||
<div class="close_button d-none position-absolute" t-ref="close_button"> |
|||
<button id="close_qr_scanner" style="position: absolute; right: 0px; z-index: 111"> |
|||
X |
|||
</button> |
|||
<div class="video-container"> |
|||
|
|||
<video id="video" width="" height="" autoplay="true"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</xpath> |
|||
</template> |
|||
</odoo> |
|||
|
|||
|
|||
|
@ -0,0 +1,33 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Template to show if the scanned QR Code is not accepted --> |
|||
<template id="redirect_to"> |
|||
<div> |
|||
<center> |
|||
<h5> |
|||
This feature is currently not available for you |
|||
</h5> |
|||
<a href="/web/login"> |
|||
<h5> |
|||
Redirect to Login Page |
|||
</h5> |
|||
</a> |
|||
</center> |
|||
</div> |
|||
</template> |
|||
<!-- Template to show if any error occurs in opening of scanner --> |
|||
<template id="be_patient"> |
|||
<div> |
|||
<center> |
|||
<h5> |
|||
Scan the QR, or else, |
|||
</h5> |
|||
<a href="/web/login"> |
|||
<h5> |
|||
Redirect to Login Page |
|||
</h5> |
|||
</a> |
|||
</center> |
|||
</div> |
|||
</template> |
|||
</odoo> |
@ -1,18 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- template to show if any error occur in opening of scanner --> |
|||
<template id="be_patient"> |
|||
<div> |
|||
<center> |
|||
<h5> |
|||
Scan the QR, or else, |
|||
</h5> |
|||
<a href="/web/login"> |
|||
<h5> |
|||
Redirect to login page |
|||
</h5> |
|||
</a> |
|||
</center> |
|||
</div> |
|||
</template> |
|||
</odoo> |
@ -1,20 +1,17 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!--adding field in res.users--> |
|||
<record id="view_users_form" model="ir.ui.view"> |
|||
<field name="name">res.users.view.form.inherit.login.using.qr</field> |
|||
<field name="model">res.users</field> |
|||
<field name="inherit_id" ref="base.view_users_form"/> |
|||
<field name="arch" type="xml"> |
|||
<data> |
|||
<!--Adding field in res.users--> |
|||
<record id="view_users_form" model="ir.ui.view"> |
|||
<field name="name">res.users.view.form.inherit.login.using.qr</field> |
|||
<field name="model">res.users</field> |
|||
<field name="inherit_id" ref="base.view_users_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//page[@name='access_rights']" position="after"> |
|||
<page string="Login QR Code" name="qr_page"> |
|||
<span>LOGIN QR</span><br/> |
|||
<field name="qr_code" class="oe_form_binary_file" widget="image"/> |
|||
</page> |
|||
</xpath> |
|||
</data> |
|||
</field> |
|||
</record> |
|||
|
|||
</field> |
|||
</record> |
|||
</odoo> |
|||
|