-
-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ce/connect messaging #35364
base: master
Are you sure you want to change the base?
Ce/connect messaging #35364
Changes from all commits
0043322
7bc3854
c609f0d
e4b6deb
929204d
79154f0
460c794
092dbe0
f29ebfc
91ce6e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ | |
) | ||
from corehq.apps.sms.mixin import BadSMSConfigException | ||
from corehq.apps.sms.models import ( | ||
ConnectMessage, | ||
INCOMING, | ||
OUTGOING, | ||
SMS, | ||
|
@@ -131,6 +132,13 @@ | |
return QueuedSMS if settings.SMS_QUEUE_ENABLED else SMS | ||
|
||
|
||
def get_message_class(phone_number): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What would you think of inlining There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds reasonable to me, I will double check usage, but it seems right |
||
if phone_number.is_sms: | ||
return get_sms_class() | ||
else: | ||
return ConnectMessage | ||
|
||
|
||
def send_sms(domain, contact, phone_number, text, metadata=None, logged_subevent=None): | ||
""" | ||
Sends an outbound SMS. Returns false if it fails. | ||
|
@@ -174,7 +182,7 @@ | |
return queue_outgoing_sms(msg) | ||
|
||
|
||
def send_sms_to_verified_number(verified_number, text, metadata=None, logged_subevent=None, events=None): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is referenced in https://github.com/dimagi/commcare-hq/blob/master/docs/messaging/outbound_sms.rst, can you update that? It'd probably be helpful to update those docs a bit more holitically, at least to mention that connect messages exist. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, I will definitely do a pass on those docs |
||
def send_message_to_verified_number(verified_number, text, metadata=None, logged_subevent=None, events=None): | ||
""" | ||
Sends an sms using the given verified phone number entry. | ||
|
||
|
@@ -192,7 +200,7 @@ | |
return False | ||
raise | ||
|
||
msg = get_sms_class()( | ||
msg = get_message_class(verified_number)( | ||
couch_recipient_doc_type=verified_number.owner_doc_type, | ||
couch_recipient=verified_number.owner_id, | ||
phone_number="+" + str(verified_number.phone_number), | ||
|
@@ -215,7 +223,10 @@ | |
msg.custom_metadata[field] = value | ||
msg.save() | ||
|
||
return queue_outgoing_sms(msg) | ||
if verified_number.is_sms: | ||
return queue_outgoing_sms(msg) | ||
else: | ||
return send_connect_message(msg, backend) | ||
|
||
|
||
def send_sms_with_backend(domain, phone_number, text, backend_id, metadata=None): | ||
|
@@ -253,7 +264,7 @@ | |
try: | ||
from corehq.apps.sms.management.commands.run_sms_queue import SMSEnqueuingOperation | ||
SMSEnqueuingOperation().enqueue(msg) | ||
except: | ||
# If this direct enqueue fails, no problem, it will get picked up | ||
# shortly. | ||
pass | ||
|
@@ -266,7 +277,7 @@ | |
msg.datetime_to_process = msg.date | ||
msg.queued_timestamp = get_utcnow() | ||
msg.save() | ||
except: | ||
log_sms_exception(msg) | ||
return False | ||
|
||
|
@@ -386,7 +397,17 @@ | |
return True | ||
|
||
|
||
def send_connect_message(message, backend): | ||
try: | ||
backend.send(message) | ||
return True | ||
except Exception: | ||
log_sms_exception(message) | ||
return False | ||
|
||
|
||
|
||
def register_sms_user( | ||
username, cleaned_phone_number, domain, send_welcome_sms=False, admin_alert_emails=None | ||
): | ||
try: | ||
|
@@ -496,7 +517,7 @@ | |
""" | ||
registration_processed = False | ||
text_words = msg.text.upper().split() | ||
keyword1 = text_words[0] if len(text_words) > 0 else "" | ||
keyword2 = text_words[1].lower() if len(text_words) > 1 else "" | ||
keyword3 = text_words[2] if len(text_words) > 2 else "" | ||
keyword4 = text_words[3] if len(text_words) > 3 else "" | ||
|
@@ -621,7 +642,7 @@ | |
for sms_handler_name in sms_handler_names: | ||
try: | ||
handler = to_function(sms_handler_name) | ||
except: | ||
notify_exception(None, message=('error loading sms handler: %s' % sms_handler_name)) | ||
continue | ||
|
||
|
@@ -685,9 +706,9 @@ | |
) | ||
|
||
|
||
def process_incoming(msg): | ||
def process_incoming(msg, phone=None): | ||
try: | ||
_process_incoming(msg) | ||
_process_incoming(msg, phone) | ||
status = 'ok' | ||
except Exception: | ||
status = 'error' | ||
|
@@ -715,9 +736,12 @@ | |
return msg.domain and domain_has_privilege(msg.domain, privileges.INBOUND_SMS) | ||
|
||
|
||
def _process_incoming(msg): | ||
def _process_incoming(msg, phone=None): | ||
sms_load_counter("inbound", msg.domain)() | ||
verified_number, has_domain_two_way_scope = get_inbound_phone_entry_from_sms(msg) | ||
if phone is None: | ||
verified_number, has_domain_two_way_scope = get_inbound_phone_entry_from_sms(msg) | ||
else: | ||
verified_number = phone | ||
is_two_way = verified_number is not None and verified_number.is_two_way | ||
|
||
if verified_number: | ||
|
@@ -746,7 +770,7 @@ | |
metadata = MessageMetadata(ignore_opt_out=True) | ||
text = get_message(MSG_OPTED_OUT, verified_number, context=(opt_in_keywords[0],)) | ||
if verified_number: | ||
send_sms_to_verified_number(verified_number, text, metadata=metadata) | ||
send_message_to_verified_number(verified_number, text, metadata=metadata) | ||
elif msg.backend_id: | ||
send_sms_with_backend(msg.domain, msg.phone_number, text, msg.backend_id, metadata=metadata) | ||
else: | ||
|
@@ -756,7 +780,7 @@ | |
if PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain): | ||
text = get_message(MSG_OPTED_IN, verified_number, context=(opt_out_keywords[0],)) | ||
if verified_number: | ||
send_sms_to_verified_number(verified_number, text) | ||
send_message_to_verified_number(verified_number, text) | ||
elif msg.backend_id: | ||
send_sms_with_backend(msg.domain, msg.phone_number, text, msg.backend_id) | ||
else: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Generated by Django 4.2.15 on 2024-10-11 13:12 | ||
|
||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('sms', '0059_remove_unicel_backend'), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterField( | ||
model_name='messagingevent', | ||
name='content_type', | ||
field=models.CharField(choices=[('NOP', 'None'), ('SMS', 'SMS Message'), ('CBK', 'SMS Expecting Callback'), ('SVY', 'SMS Survey'), ('IVR', 'IVR Survey'), ('VER', 'Phone Verification'), ('ADH', 'Manually Sent Message'), ('API', 'Message Sent Via API'), ('CHT', 'Message Sent Via Chat'), ('EML', 'Email'), ('FCM', 'FCM Push Notification'), ('CON', 'Connect Message')], max_length=3), | ||
), | ||
migrations.AlterField( | ||
model_name='messagingsubevent', | ||
name='content_type', | ||
field=models.CharField(choices=[('NOP', 'None'), ('SMS', 'SMS Message'), ('CBK', 'SMS Expecting Callback'), ('SVY', 'SMS Survey'), ('IVR', 'IVR Survey'), ('VER', 'Phone Verification'), ('ADH', 'Manually Sent Message'), ('API', 'Message Sent Via API'), ('CHT', 'Message Sent Via Chat'), ('EML', 'Email'), ('FCM', 'FCM Push Notification'), ('CON', 'Connect Message')], max_length=3), | ||
), | ||
migrations.CreateModel( | ||
name='ConnectMessage', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('domain', models.CharField(db_index=True, max_length=126, null=True)), | ||
('date', models.DateTimeField(db_index=True, null=True)), | ||
('couch_recipient_doc_type', models.CharField(db_index=True, max_length=126, null=True)), | ||
('couch_recipient', models.CharField(db_index=True, max_length=126, null=True)), | ||
('phone_number', models.CharField(db_index=True, max_length=126, null=True)), | ||
('direction', models.CharField(max_length=1, null=True)), | ||
('error', models.BooleanField(default=False, null=True)), | ||
('system_error_message', models.TextField(null=True)), | ||
('system_phone_number', models.CharField(max_length=126, null=True)), | ||
('backend_api', models.CharField(max_length=126, null=True)), | ||
('backend_id', models.CharField(max_length=126, null=True)), | ||
('billed', models.BooleanField(default=False, null=True)), | ||
('workflow', models.CharField(max_length=126, null=True)), | ||
('xforms_session_couch_id', models.CharField(db_index=True, max_length=126, null=True)), | ||
('reminder_id', models.CharField(max_length=126, null=True)), | ||
('location_id', models.CharField(max_length=126, null=True)), | ||
('date_modified', models.DateTimeField(auto_now=True, db_index=True, null=True)), | ||
('text', models.CharField(max_length=300)), | ||
('messaging_subevent', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='sms.messagingsubevent')), | ||
], | ||
options={ | ||
'abstract': False, | ||
}, | ||
), | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's weird that connectid is one word. I do see that it's consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think of
connectid
as its own thing (its a separate repo and site than connect), using one word feels like it implies that, rather than the id for connect, but I am not wedded to it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connectid
and "the id for connect` being two separate concepts sounds confusing, but I don't think I have enough context on the project to be certain or to make a better suggestion.