Skip to content

Commit 22c29a5

Browse files
committed
add example app code for testing template-only-app
1 parent affb7c7 commit 22c29a5

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

template-only-app/app.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from flask import Flask, redirect, render_template, request
77

88
import notifications
9+
import sms_notifications
910
import storage
1011
from db import get_db_connection
1112
from feature_flags import is_feature_enabled
@@ -106,6 +107,28 @@ def cron():
106107
conn.execute("SELECT 1")
107108
print("Hello from cron job")
108109

110+
@app.route("/sms-notifications", methods=["GET", "POST"])
111+
def sms_notifications_page():
112+
logger.info("Accessed /sms-notifications endpoint with method %s", request.method)
113+
if request.method == "POST":
114+
phone_number = request.form.get("phone_number")
115+
message = "This is a test SMS from Strata Platform."
116+
117+
# Check opt-out status first
118+
opt_out_status = sms_notifications.check_opt_out_status(phone_number)
119+
if opt_out_status.get("opted_out"):
120+
return f"Cannot send SMS: {phone_number} has opted out of messages."
121+
122+
# Send SMS
123+
result = sms_notifications.send_sms(phone_number, message)
124+
logger.info("SMS send result: %s", result)
125+
126+
if result["success"]:
127+
return f"SMS sent successfully to {phone_number}. Message ID: {result['message_id']}"
128+
else:
129+
return f"Failed to send SMS: {result['error']} (Code: {result.get('error_code', 'Unknown')})"
130+
131+
return render_template("sms_form.html")
109132

110133
if __name__ == "__main__":
111134
main()
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import logging
2+
import os
3+
import boto3
4+
import json
5+
from botocore.exceptions import ClientError
6+
7+
logging.basicConfig()
8+
logger = logging.getLogger()
9+
logger.setLevel(logging.INFO)
10+
11+
def send_sms(phone_number, message, message_type="TRANSACTIONAL"):
12+
"""
13+
Send SMS via AWS End User Messaging (PinpointSMSVoiceV2)
14+
"""
15+
try:
16+
logger.info("Initializing AWS Pinpoint SMS Voice V2 client")
17+
client = boto3.client("pinpoint-sms-voice-v2")
18+
phone_pool_id = os.environ.get("AWS_SMS_PHONE_POOL_ID")
19+
configuration_set = os.environ.get("AWS_SMS_CONFIGURATION_SET_NAME")
20+
logger.info("Sending SMS Using Configuration Set: %s", configuration_set)
21+
logger.info("Sending SMS Using Phone Pool ID: %s", phone_pool_id)
22+
23+
params = {
24+
"DestinationPhoneNumber": phone_number,
25+
"OriginationIdentity": phone_pool_id,
26+
"MessageBody": message,
27+
"MessageType": message_type
28+
}
29+
30+
# Add configuration set for tracking
31+
if configuration_set:
32+
params["ConfigurationSetName"] = configuration_set
33+
34+
# Add context for tracking (optional)
35+
params["Context"] = {
36+
"ApplicationName": "template-app",
37+
"Environment": "dev"
38+
}
39+
40+
if check_opt_out_status(phone_number).get("opted_out"):
41+
logger.warning("Phone number %s has opted out of SMS messages. Aborting send.", phone_number)
42+
return {
43+
"success": False,
44+
"error": f"Phone number {phone_number} has opted out of SMS messages."
45+
}
46+
47+
response = client.send_text_message(**params)
48+
49+
return {
50+
"success": True,
51+
"message_id": response.get("MessageId"),
52+
"response": response
53+
}
54+
55+
except ClientError as e:
56+
error_code = e.response["Error"]["Code"]
57+
error_message = e.response["Error"]["Message"]
58+
logger.error(f"ClientError: {error_code} - {error_message}")
59+
60+
return {
61+
"success": False,
62+
"error": error_message,
63+
"error_code": error_code,
64+
"details": str(e)
65+
}
66+
except Exception as e:
67+
return {
68+
"success": False,
69+
"error": str(e)
70+
}
71+
72+
def check_opt_out_status(phone_number):
73+
"""
74+
Check if a phone number is opted out
75+
"""
76+
try:
77+
client = boto3.client("pinpoint-sms-voice-v2")
78+
79+
response = client.describe_opted_out_numbers(
80+
OptOutListName="default",
81+
OptedOutNumbers=[phone_number]
82+
)
83+
84+
opted_out_numbers = response.get("OptedOutNumbers", [])
85+
is_opted_out = any(num["OptedOutNumber"] == phone_number for num in opted_out_numbers)
86+
87+
return {"opted_out": is_opted_out}
88+
89+
except Exception as e:
90+
return {"error": str(e)}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>SMS Test</title>
5+
</head>
6+
<body>
7+
<h1>Send Test SMS</h1>
8+
<form method="post">
9+
<div>
10+
<label for="phone_number">Receiver Phone Number (E.164 format: +1234567890):</label><br>
11+
<input type="tel" id="phone_number" name="phone_number"
12+
pattern="^\+[1-9]\d{1,14}$"
13+
placeholder="+1234567890"
14+
required><br>
15+
<small>Must include country code (e.g., +1 for US)</small><br>
16+
<small><strong>If using simulator phone numbers for testing:</strong><br>
17+
• +14254147755 (Success Text testing)<br>
18+
• +14254147167 (Text Blocked testing)</small>
19+
</div>
20+
<br>
21+
<button type="submit">Send Test SMS</button>
22+
</form>
23+
</body>
24+
</html>

0 commit comments

Comments
 (0)