-
-
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
Conversation
6a953fa
to
f22c90d
Compare
f22c90d
to
460c794
Compare
@@ -174,7 +182,7 @@ def send_sms(domain, contact, phone_number, text, metadata=None, logged_subevent | |||
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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I will definitely do a pass on those docs
@@ -131,6 +132,13 @@ def get_sms_class(): | |||
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 comment
The reason will be displayed to describe this comment to others. Learn more.
What would you think of inlining get_sms_class
into this function? Seems a little nicer to have calling code always use this function instead of needing to know when to call this vs get_sms_class
.
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.
Sounds reasonable to me, I will double check usage, but it seems right
from django.db import migrations, models | ||
import uuid | ||
|
||
class Migration(migrations.Migration): |
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 it's standard to squash all the migrations for a single PR, just to reduce the number of migrations in the repo long-term.
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.
Yep, I plan do that
class ConnectMessage(Log): | ||
date_modified = models.DateTimeField(null=True, db_index=True, auto_now=True) | ||
text = models.CharField(max_length=300) | ||
received_on = models.DateTimeField(null=True, blank=True) |
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.
Why would this be blank/null? I'd expected this to default to now.
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.
Outgoing messages won't have a received timestamp until they get to the phone and the phone acknowledges them
@property | ||
@abstractmethod | ||
def backend(self): | ||
pass |
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.
Can these raise NotImplementedError
s, or does this being an abstract class take care of complaining if a subclass doesn't implement all of the necessary methods?
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.
Oh, I meant to get rid of this class entirely. I had originally planned to have the ConnectNumber
and the old PhoneNumber
class inherit from it, and treat it as an interface the rest of the messaging code could use, but it turns out its difficult to use abstract base classes with django models because they both do weird things to the class Meta
. I may still try to find a way to get both to pass the same type check, but I dont think this class is the answer.
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.
grand
@@ -513,9 +520,9 @@ def get_layout_fields(self): | |||
data_bind='with: message', | |||
), | |||
data_bind=( | |||
"visible: $root.content() === '%s' || $root.content() === '%s' " |
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.
A f string would make this a whole lot better.
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.
good call. I can make that change
@@ -534,10 +541,11 @@ def get_layout_fields(self): | |||
), | |||
data_bind=( | |||
"visible: $root.content() === '%s' || $root.content() === '%s' " | |||
"|| $root.content() === '%s' " | |||
"|| $root.content() === '%s' || $root.content() === '%s' " |
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.
Same comment about f strings.
@@ -1757,6 +1770,10 @@ def create_form_helper(): | |||
def form_choices(self): | |||
return [(form['code'], form['name']) for form in get_form_list(self.domain)] | |||
|
|||
@property | |||
def can_use_connect(self): |
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.
Nitpick: is this better than just having the calling code check the feature flag?
@@ -405,3 +407,19 @@ def user_can_access_domain_specific_pages(request): | |||
return False | |||
|
|||
return couch_user.is_member_of(project) or (couch_user.is_superuser and not project.restrict_superusers) | |||
|
|||
|
|||
def connectid_token_auth(view_func): |
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.
preserve_default=False, | ||
), | ||
migrations.AddField( | ||
model_name='connectmessagesurveycontent', | ||
name='form_unique_id', | ||
field=models.CharField(default=1, max_length=126), | ||
field=models.CharField(default="1", max_length=126), |
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.
Why not just allow this to be blank? Or does 1 have a meaning?
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.
Nope, this will be unnecessary once we combine the migrations as you mentioned above, we just needed any value to have a valid migration, even though that table was empty when I made this one, so it is never used.
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.
In general this looks good to me but I'm not able to fully review all the implications of the changes.
Product Description
This adds connect messaging as a new message type in the messaging framework. It does not currently support form sessions although I will add those prior to merge. That said, I wanted to open this up to review now since it is quite large and touches a fair amount of complex code.
Technical Summary
Tech Spec: https://docs.google.com/document/d/1FgsXr0PLR7Btq2fOBeXIMs_OziBRsUsATgHgWna0h5M/edit?tab=t.0#heading=h.3rzu21agk2m3
Design Doc: https://docs.google.com/document/d/1h3bcZ4oQAnOu5aGW8Rue0TnbiaW2OXWMaqNKwI6RciE/edit?tab=t.0#heading=h.ipgou4bu0qoj
The linked docs provide much of the context
Feature Flag
COMMCARE_CONNECT for now, but I expect to migrate it to its own flag so that it can be enabled independently of the rest of the connect features.
Safety Assurance
Safety story
Existing messaging paths have automated coverage, and are only minimally modified. The new code is almost entirely self contained and will go through a QA process.
Automated test coverage
QA Plan
No QA ticket yet since it is not finished, but I will add it once it starts.
Migrations
Rollback instructions
Labels & Review