From ed285d29fb694613836fab1e13dcbf7ecf345246 Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Mon, 10 Oct 2022 09:35:10 +0200
Subject: [PATCH 07/10] utils: add registration sms code sending logic (#69223)

---
 .../registration/sms_code_registration.txt    |  1 +
 src/authentic2/utils/misc.py                  | 63 +++++++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 src/authentic2/templates/registration/sms_code_registration.txt

diff --git a/src/authentic2/templates/registration/sms_code_registration.txt b/src/authentic2/templates/registration/sms_code_registration.txt
new file mode 100644
index 000000000..f16b234ae
--- /dev/null
+++ b/src/authentic2/templates/registration/sms_code_registration.txt
@@ -0,0 +1 @@
+{% load i18n %}{% blocktrans trimmed with value=code.value %}Your code is {{ value }}{% endblocktrans %}
\ No newline at end of file
diff --git a/src/authentic2/utils/misc.py b/src/authentic2/utils/misc.py
index 0af4cde14..895484a3f 100644
--- a/src/authentic2/utils/misc.py
+++ b/src/authentic2/utils/misc.py
@@ -34,6 +34,7 @@ from django.contrib.auth import get_user_model
 from django.contrib.auth import login as auth_login
 from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured, ValidationError
 from django.core.mail import EmailMessage, send_mail
+from django.db import transaction
 from django.forms.utils import ErrorList, to_current_timezone
 from django.http import HttpResponse, HttpResponseRedirect
 from django.http.request import QueryDict
@@ -45,12 +46,14 @@ from django.utils import html, timezone
 from django.utils.encoding import iri_to_uri, uri_to_iri
 from django.utils.formats import localize
 from django.utils.translation import ngettext
+from requests import RequestException
 
 from authentic2.saml.saml2utils import filter_attribute_private_key, filter_element_private_key
 from authentic2.validators import EmailValidator
 
 from .. import app_settings, constants, crypto, plugins
 from .cache import GlobalCache
+from .requests_wrapper import Requests
 
 
 class CleanLogMessage(logging.Filter):
@@ -792,6 +795,66 @@ def build_deletion_url(request, **kwargs):
     return delete_url
 
 
+def generate_code(phone_number):
+    from authentic2.models import SMSCode
+
+    return SMSCode.create(
+        phone_number,
+        kind='registration',
+    )
+
+
+class SMSError(Exception):
+    pass
+
+
+def send_registration_sms(request, phone_number, ou, template_names=None, context=None, **kwargs):
+    """Sends a registration code sms to a user, the latter inputs the received code
+    in a dedicated form to validate their account creation.
+    """
+
+    logger = logging.getLogger(__name__)
+
+    sender = settings.SMS_SENDER
+    url = settings.SMS_URL
+    message = render
+    requests = Requests()  # Publik signature requests wrapper
+
+    if not sender:
+        logger.error('settings.SMS_SENDER is not set')
+        raise SMSError('SMS improperly configured')
+    if not url:
+        logger.error('settings.SMS_URL is not set')
+        raise SMSError('SMS improperly configured')
+
+    if not template_names:
+        template_names = ['registration/sms_code_registration.txt']
+    if not isinstance(context, dict):
+        context = {}
+
+    code = generate_code(phone_number)
+    context.update({'code': code})
+
+    message = render_plain_text_template_to_string(template_names, context)
+
+    payload = {
+        'message': message,
+        'from': sender,
+        'to': phone_number,
+    }
+
+    try:
+        with transaction.atomic():
+            response = requests.post(url, json=payload, timeout=10)
+            response.raise_for_status()
+            code.sent = True
+            code.save()
+    except RequestException as e:
+        logger.warning('sms registration to %s using %s failed: %s', phone_number, url, e)
+        raise SMSError(f'Error while contacting SMS service: {e}')
+    return code
+
+
 def send_registration_mail(request, email, ou, template_names=None, next_url=None, context=None, **kwargs):
     """Send a registration mail to an user. All given kwargs will be used
     to completed the user model.
-- 
2.37.2

