[FIX] otp_sms_auth_custom
This commit is contained in:
parent
3836301242
commit
e4ee09e9c1
|
|
@ -8,6 +8,7 @@
|
|||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/res_users_view.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': False,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ class AuthSignInHome(Home):
|
|||
if user:
|
||||
data['status'] = True
|
||||
data['msg'] = 'OTP is generated and sent successfully'
|
||||
data['otp'] = user.generate_otp() if user else ""
|
||||
# data['otp'] = user.generate_otp() if user else ""
|
||||
user.generate_otp()
|
||||
|
||||
return json.dumps(data)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import res_config_settings
|
||||
from . import res_users
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
import random
|
||||
import requests
|
||||
import logging
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
# -- SMS API Settings --
|
||||
sms_mode = fields.Selection(
|
||||
[('test', 'Test Mode (Disable SMS Sending)'), ('prod', 'Production')],
|
||||
string="SMS Mode",
|
||||
default='test',
|
||||
required=True,
|
||||
help="In Test Mode, OTP will be generated and logged but no SMS will be sent."
|
||||
)
|
||||
sms_api_url = fields.Char(string="SMS API URL")
|
||||
sms_api_token = fields.Char(string="SMS API Token", help="Your Bearer token for the SMS API.")
|
||||
sms_sender_name = fields.Char(string="SMS Sender Name")
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
# -- SMS API Settings --
|
||||
# The 'related' attribute links these transient fields to the fields on res.company
|
||||
sms_mode = fields.Selection(
|
||||
related='company_id.sms_mode',
|
||||
readonly=False,
|
||||
required=True
|
||||
)
|
||||
sms_api_url = fields.Char(
|
||||
related='company_id.sms_api_url',
|
||||
readonly=False
|
||||
)
|
||||
sms_api_token = fields.Char(
|
||||
related='company_id.sms_api_token',
|
||||
readonly=False
|
||||
)
|
||||
sms_sender_name = fields.Char(
|
||||
related='company_id.sms_sender_name',
|
||||
readonly=False
|
||||
)
|
||||
|
|
@ -15,45 +15,57 @@ class ResUsersInherit(models.Model):
|
|||
otp_mobile_phone = fields.Char(string="Mobile Phone")
|
||||
otp_code = fields.Char(string="OTP Code", readonly=True)
|
||||
|
||||
|
||||
def generate_otp(self):
|
||||
"""Generate a random OTP and send via SMS."""
|
||||
"""
|
||||
Generate a random OTP, save it, and send it via SMS based on company settings.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if not self.otp_mobile_phone:
|
||||
raise ValidationError("No mobile phone number provided for OTP.")
|
||||
|
||||
# Get the configuration from the user's current company
|
||||
company = self.env.company
|
||||
|
||||
# Generate OTP regardless of mode
|
||||
otp = str(random.randint(1000, 9999))
|
||||
self.otp_code = otp
|
||||
|
||||
# Taqnyat SMS API details
|
||||
api_url = "https://api.taqnyat.sa/v1/messages"
|
||||
api_token = "0d275c8a69ae5f1a6fd0fca19137db57"
|
||||
sender_name = "ENSAN"
|
||||
# Check the SMS mode
|
||||
if company.sms_mode == 'test':
|
||||
_logger.info(f"--- SMS TEST MODE --- OTP for user {self.name} is {otp}. SMS not sent.")
|
||||
# In test mode, we can return the OTP directly for testing purposes
|
||||
return otp
|
||||
|
||||
# --- Production Mode Logic ---
|
||||
# Validate that all configuration fields are set
|
||||
if not all([company.sms_api_url, company.sms_api_token, company.sms_sender_name]):
|
||||
raise ValidationError("SMS API settings (URL, Token, Sender Name) are not fully configured in General Settings.")
|
||||
|
||||
# SMS payload
|
||||
payload = {
|
||||
"recipients": [self.otp_mobile_phone],
|
||||
"body": f"Your OTP code is: {otp}",
|
||||
"sender": sender_name,
|
||||
"sender": company.sms_sender_name,
|
||||
}
|
||||
|
||||
# Headers for authentication
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_token}",
|
||||
"Authorization": f"Bearer {company.sms_api_token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
# Send the SMS
|
||||
try:
|
||||
response = requests.post(api_url, json=payload, headers=headers)
|
||||
response = requests.post(company.sms_api_url, json=payload, headers=headers, timeout=10)
|
||||
response.raise_for_status() # Raise an error for non-2xx responses
|
||||
_logger.info(f"OTP {otp} sent successfully to {self.otp_mobile_phone}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
_logger.error(f"Failed to send OTP to {self.otp_mobile_phone}: {e}")
|
||||
raise ValueError("Failed to send OTP. Please try again later.")
|
||||
raise ValidationError("Failed to send OTP. Please check API configuration or try again later.")
|
||||
|
||||
return otp
|
||||
|
||||
|
||||
def validate_otp(self, otp):
|
||||
"""Validate the OTP."""
|
||||
self.ensure_one()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="res_config_settings_view_form_sms_api" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.view.form.inherit.sms.api</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[@id='business_documents']" position="after">
|
||||
<h2>SMS API Configuration</h2>
|
||||
<div class="row mt16 o_settings_container" id="sms_api_settings">
|
||||
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_right_pane">
|
||||
<span class="o_form_label">Mode</span>
|
||||
<div class="text-muted">
|
||||
Enable or disable SMS sending
|
||||
</div>
|
||||
<div class="content-group">
|
||||
<div class="row mt16">
|
||||
<label for="sms_mode" class="col-lg-3 o_light_label"/>
|
||||
<field name="sms_mode"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-lg-6 o_setting_box" attrs="{'invisible': [('sms_mode', '=', 'test')]}">
|
||||
<div class="o_setting_right_pane">
|
||||
<span class="o_form_label">API Credentials</span>
|
||||
<div class="text-muted">
|
||||
Credentials for your SMS provider
|
||||
</div>
|
||||
<div class="content-group">
|
||||
<div class="row mt16">
|
||||
<label for="sms_api_url" string="API URL" class="col-lg-4 o_light_label"/>
|
||||
<field name="sms_api_url" attrs="{'required': [('sms_mode', '=', 'prod')]}" placeholder="e.g. https://api.twilio.com/2010-04-01/Accounts/AC.../Messages.json"/>
|
||||
</div>
|
||||
<div class="row mt16">
|
||||
<label for="sms_api_token" string="API Token" class="col-lg-4 o_light_label"/>
|
||||
<field name="sms_api_token" attrs="{'required': [('sms_mode', '=', 'prod')]}" password="True"/>
|
||||
</div>
|
||||
<div class="row mt16">
|
||||
<label for="sms_sender_name" string="Sender Name" class="col-lg-4 o_light_label"/>
|
||||
<field name="sms_sender_name" attrs="{'required': [('sms_mode', '=', 'prod')]}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue