Coverage for src/couchers/phone/sms.py: 100%
26 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-12-20 18:03 +0000
« prev ^ index » next coverage.py v7.5.0, created at 2024-12-20 18:03 +0000
1import logging
3import boto3
4import luhn
6from couchers import crypto
7from couchers.config import config
8from couchers.db import session_scope
9from couchers.models import SMS
11logger = logging.getLogger(__name__)
14def generate_random_code():
15 """Return a random 6-digit string with correct Luhn checksum"""
16 return luhn.append(crypto.generate_random_5digit_string())
19def looks_like_a_code(string):
20 return len(string) == 6 and string.isdigit() and luhn.verify(string)
23def format_message(token):
24 return f"{token} is your Couchers.org verification code. If you did not request this, please ignore this message. Best, the Couchers.org team."
27def send_sms(number, message):
28 """Send SMS to a E.164 formatted phone number with leading +. Return "success" on
29 success, "unsupported operator" on unsupported operator, and any other
30 string for any other error."""
32 assert len(message) <= 140, "Message too long"
34 if not config["ENABLE_SMS"]:
35 logger.info(f"SMS not enabled, need to send to {number}: {message}")
36 return "SMS not enabled."
38 sns = boto3.client("sns")
39 sender_id = config["SMS_SENDER_ID"]
41 response = sns.publish(
42 PhoneNumber=number,
43 Message=message,
44 MessageAttributes={
45 "AWS.SNS.SMS.SMSType": {"DataType": "String", "StringValue": "Transactional"},
46 "AWS.SNS.SMS.SenderID": {"DataType": "String", "StringValue": sender_id},
47 },
48 )
50 message_id = response["MessageId"]
52 with session_scope() as session:
53 session.add(
54 SMS(
55 message_id=message_id,
56 number=number,
57 message=message,
58 sms_sender_id=sender_id,
59 )
60 )
62 return "success"