def start_smsforms_session(self, domain, recipient, case_id, phone_entry_or_number, logged_subevent, workflow, app, module, form): # Close all currently open sessions SQLXFormsSession.close_all_open_sms_sessions(domain, recipient.get_id) # Start the new session try: session, responses = start_session( SQLXFormsSession.create_session_object( domain, recipient, (phone_entry_or_number.phone_number if isinstance(phone_entry_or_number, PhoneNumber) else phone_entry_or_number), app, form, expire_after=self.expire_after, reminder_intervals=self.reminder_intervals, submit_partially_completed_forms=self.submit_partially_completed_forms, include_case_updates_in_partial_submissions=self.include_case_updates_in_partial_submissions ), domain, recipient, app, module, form, case_id, yield_responses=True ) except TouchformsError as e: logged_subevent.error( MessagingEvent.ERROR_TOUCHFORMS_ERROR, additional_error_text=get_formplayer_exception(domain, e) ) if touchforms_error_is_config_error(domain, e): # Don't reraise the exception because this means there are configuration # issues with the form that need to be fixed. The error is logged in the # above lines. return None, None # Reraise the exception so that the framework retries it again later raise except: logged_subevent.error(MessagingEvent.ERROR_TOUCHFORMS_ERROR) # Reraise the exception so that the framework retries it again later raise session.workflow = workflow session.save() return session, responses
def start_smsforms_session(self, domain, recipient, case_id, phone_entry_or_number, logged_subevent, workflow, app, module, form): # Close all currently open sessions SQLXFormsSession.close_all_open_sms_sessions(domain, recipient.get_id) # Start the new session try: session, responses = start_session( SQLXFormsSession.create_session_object( domain, recipient, (phone_entry_or_number.phone_number if isinstance(phone_entry_or_number, PhoneNumber) else phone_entry_or_number), app, form, expire_after=self.expire_after, reminder_intervals=self.reminder_intervals, submit_partially_completed_forms=self.submit_partially_completed_forms, include_case_updates_in_partial_submissions=self.include_case_updates_in_partial_submissions ), domain, recipient, app, module, form, case_id, ) except TouchformsError as e: logged_subevent.error( MessagingEvent.ERROR_TOUCHFORMS_ERROR, additional_error_text=get_formplayer_exception(domain, e) ) if touchforms_error_is_config_error(domain, e): # Don't reraise the exception because this means there are configuration # issues with the form that need to be fixed. The error is logged in the # above lines. return None, None # Reraise the exception so that the framework retries it again later raise except: logged_subevent.error(MessagingEvent.ERROR_TOUCHFORMS_ERROR) # Reraise the exception so that the framework retries it again later raise session.workflow = workflow session.save() return session, responses
def test_get_and_close_all_open_sessions(self): domain = uuid.uuid4().hex contact = uuid.uuid4().hex for i in range(3): _make_session( domain=domain, connection_id=contact, end_time=None, session_type=XFORMS_SESSION_SMS, ) sql_sessions = SQLXFormsSession.get_all_open_sms_sessions(domain, contact) self.assertEqual(3, len(sql_sessions)) SQLXFormsSession.close_all_open_sms_sessions(domain, contact) self.assertEqual(0, len(SQLXFormsSession.get_all_open_sms_sessions(domain, contact)))
def test_get_and_close_all_open_sessions(self): domain = uuid.uuid4().hex contact = uuid.uuid4().hex for i in range(3): _make_session( domain=domain, connection_id=contact, end_time=None, session_type=XFORMS_SESSION_SMS, ) sql_sessions = SQLXFormsSession.get_all_open_sms_sessions(domain, contact) self.assertEqual(3, len(sql_sessions)) SQLXFormsSession.close_all_open_sms_sessions(domain, contact) self.assertEqual(0, len(SQLXFormsSession.get_all_open_sms_sessions(domain, contact)))
def process_survey_keyword_actions(verified_number, survey_keyword, text, msg): sender = verified_number.owner case = None args = split_args(text, survey_keyword) logged_event = MessagingEvent.create_from_keyword(survey_keyword, sender) # Close any open sessions even if it's just an sms that we're # responding with. SQLXFormsSession.close_all_open_sms_sessions(verified_number.domain, verified_number.owner_id) if sender.doc_type == "CommCareCase": case = sender args = args[1:]
def process_survey_keyword_actions(verified_number, survey_keyword, text, msg): sender = verified_number.owner case = None args = split_args(text, survey_keyword) logged_event = MessagingEvent.create_from_keyword(survey_keyword, sender) # Log a messaging subevent for the incoming message subevent = logged_event.create_subevent_for_single_sms( msg.couch_recipient_doc_type, msg.couch_recipient, completed=True) add_msg_tags(msg, MessageMetadata(messaging_subevent_id=subevent.pk)) # Close any open sessions even if it's just an sms that we're # responding with. SQLXFormsSession.close_all_open_sms_sessions(verified_number.domain, verified_number.owner_id) if is_commcarecase(sender): case = sender args = args[1:]
def global_keyword_stop(v, text, msg, text_words, open_sessions): SQLXFormsSession.close_all_open_sms_sessions(v.domain, v.owner_id) return True
def process_survey_keyword_actions(verified_number, survey_keyword, text, msg): sender = verified_number.owner case = None args = split_args(text, survey_keyword) logged_event = MessagingEvent.create_from_keyword(survey_keyword, sender) # Log a messaging subevent for the incoming message subevent = logged_event.create_subevent_for_single_sms( msg.couch_recipient_doc_type, msg.couch_recipient ) subevent.completed() add_msg_tags(msg, MessageMetadata(messaging_subevent_id=subevent.pk)) # Close any open sessions even if it's just an sms that we're # responding with. SQLXFormsSession.close_all_open_sms_sessions(verified_number.domain, verified_number.owner_id) if sender.doc_type == "CommCareCase": case = sender args = args[1:] elif sender.doc_type == "CommCareUser": if keyword_uses_form_that_requires_case(survey_keyword): if len(args) > 1: external_id = args[1] case, matches = get_case_by_external_id(verified_number.domain, external_id, sender) if matches == 0: send_keyword_response(verified_number, MSG_CASE_NOT_FOUND, logged_event) logged_event.error(MessagingEvent.ERROR_CASE_EXTERNAL_ID_NOT_FOUND) return elif matches > 1: send_keyword_response(verified_number, MSG_MULTIPLE_CASES_FOUND, logged_event) logged_event.error(MessagingEvent.ERROR_MULTIPLE_CASES_WITH_EXTERNAL_ID_FOUND) return else: send_keyword_response(verified_number, MSG_MISSING_EXTERNAL_ID, logged_event) logged_event.error(MessagingEvent.ERROR_NO_EXTERNAL_ID_GIVEN) return args = args[2:] else: args = args[1:] def cmp_fcn(a1, a2): a1_ss = (a1.action == METHOD_STRUCTURED_SMS) a2_ss = (a2.action == METHOD_STRUCTURED_SMS) if a1_ss and a2_ss: return 0 elif a1_ss: return -1 elif a2_ss: return 1 else: return 0 if case: subevent.case_id = case.get_id subevent.save() # Process structured sms actions first actions = sorted(survey_keyword.actions, cmp=cmp_fcn) for survey_keyword_action in actions: if survey_keyword_action.recipient == RECIPIENT_SENDER: contact = sender elif survey_keyword_action.recipient == RECIPIENT_OWNER: if sender.doc_type == "CommCareCase": contact = get_wrapped_owner(get_owner_id(sender)) else: contact = None elif survey_keyword_action.recipient == RECIPIENT_USER_GROUP: try: contact = Group.get(survey_keyword_action.recipient_id) assert contact.doc_type == "Group" assert contact.domain == verified_number.domain except Exception: contact = None else: contact = None if contact is None: continue if survey_keyword_action.action == METHOD_SMS: create_immediate_reminder(contact, METHOD_SMS, reminder_type=REMINDER_TYPE_KEYWORD_INITIATED, message=survey_keyword_action.message_content, case=case, logged_event=logged_event) elif survey_keyword_action.action == METHOD_SMS_SURVEY: create_immediate_reminder(contact, METHOD_SMS_SURVEY, reminder_type=REMINDER_TYPE_KEYWORD_INITIATED, form_unique_id=survey_keyword_action.form_unique_id, case=case, logged_event=logged_event) elif survey_keyword_action.action == METHOD_STRUCTURED_SMS: res = handle_structured_sms(survey_keyword, survey_keyword_action, sender, verified_number, text, send_response=True, msg=msg, case=case, text_args=args, logged_event=logged_event) if not res: # If the structured sms processing wasn't successful, don't # process any of the other actions return logged_event.completed()
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers, logged_event): if reminder.callback_try_count > 0: # Handle timeouts if handler.submit_partial_forms and ( reminder.callback_try_count == len(reminder.current_event.callback_timeout_intervals) ): # Submit partial form completions for session_id in reminder.xforms_session_ids: submit_unfinished_form(session_id, handler.include_case_side_effects) else: # Resend current question for session_id in reminder.xforms_session_ids: session = get_session_by_session_id(session_id) if session.end_time is None: vn = VerifiedNumber.view( "sms/verified_number_by_owner_id", key=session.connection_id, include_docs=True ).first() if vn is not None: metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) resp = current_question(session_id) send_sms_to_verified_number(vn, resp.event.text_prompt, metadata) else: reminder.xforms_session_ids = [] domain_obj = Domain.get_by_name(reminder.domain, strict=True) # Get the app, module, and form try: form_unique_id = reminder.current_event.form_unique_id form = Form.get_form(form_unique_id) app = form.get_app() module = form.get_module() except Exception: logged_event.error(MessagingEvent.ERROR_CANNOT_FIND_FORM) return # Start a touchforms session for each recipient for recipient in recipients: logged_subevent = logged_event.create_subevent(handler, reminder, recipient) verified_number, unverified_number = get_recipient_phone_number(reminder, recipient, verified_numbers) no_verified_number = verified_number is None cant_use_unverified_number = ( unverified_number is None or not domain_obj.send_to_duplicated_case_numbers or form_requires_input(form) ) if no_verified_number and cant_use_unverified_number: logged_subevent.error(MessagingEvent.ERROR_NO_TWO_WAY_PHONE_NUMBER) continue key = "start-sms-survey-for-contact-%s" % recipient.get_id with CriticalSection([key], timeout=60): # Get the case to submit the form against, if any if isinstance(recipient, CommCareCase) and not handler.force_surveys_to_use_triggered_case: case_id = recipient.get_id else: case_id = reminder.case_id if form.requires_case() and not case_id: logged_subevent.error(MessagingEvent.ERROR_NO_CASE_GIVEN) continue # Close all currently open sessions SQLXFormsSession.close_all_open_sms_sessions(reminder.domain, recipient.get_id) # Start the new session try: session, responses = start_session( reminder.domain, recipient, app, module, form, case_id, case_for_case_submission=handler.force_surveys_to_use_triggered_case, ) except TouchformsError as e: human_readable_message = e.response_data.get("human_readable_message", None) logged_subevent.error( MessagingEvent.ERROR_TOUCHFORMS_ERROR, additional_error_text=human_readable_message ) if touchforms_error_is_config_error(e): # Don't reraise the exception because this means there are configuration # issues with the form that need to be fixed continue else: # Reraise the exception so that the framework retries it again later raise except Exception as e: logged_subevent.error(MessagingEvent.ERROR_TOUCHFORMS_ERROR) # Reraise the exception so that the framework retries it again later raise session.survey_incentive = handler.survey_incentive session.workflow = get_workflow(handler) session.reminder_id = reminder._id session.save() reminder.xforms_session_ids.append(session.session_id) logged_subevent.xforms_session = session logged_subevent.save() # Send out first message if len(responses) > 0: message = format_message_list(responses) metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id ) if verified_number: send_sms_to_verified_number(verified_number, message, metadata) else: send_sms(reminder.domain, recipient, unverified_number, message, metadata) logged_subevent.completed()
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers, logged_event): if reminder.callback_try_count > 0: # Handle timeouts if handler.submit_partial_forms and ( reminder.callback_try_count == len( reminder.current_event.callback_timeout_intervals)): # Submit partial form completions for session_id in reminder.xforms_session_ids: submit_unfinished_form(session_id, handler.include_case_side_effects) else: # Resend current question for session_id in reminder.xforms_session_ids: session = get_session_by_session_id(session_id) if session.end_time is None: vn = VerifiedNumber.view("sms/verified_number_by_owner_id", key=session.connection_id, include_docs=True).first() if vn is not None: metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) resp = current_question(session_id) send_sms_to_verified_number(vn, resp.event.text_prompt, metadata) else: reminder.xforms_session_ids = [] domain_obj = Domain.get_by_name(reminder.domain, strict=True) # Get the app, module, and form try: form_unique_id = reminder.current_event.form_unique_id form = Form.get_form(form_unique_id) app = form.get_app() module = form.get_module() except Exception: logged_event.error(MessagingEvent.ERROR_CANNOT_FIND_FORM) return # Start a touchforms session for each recipient for recipient in recipients: logged_subevent = logged_event.create_subevent( handler, reminder, recipient) verified_number, unverified_number = get_recipient_phone_number( reminder, recipient, verified_numbers) no_verified_number = verified_number is None cant_use_unverified_number = ( unverified_number is None or not domain_obj.send_to_duplicated_case_numbers or form_requires_input(form)) if no_verified_number and cant_use_unverified_number: logged_subevent.error( MessagingEvent.ERROR_NO_TWO_WAY_PHONE_NUMBER) continue key = "start-sms-survey-for-contact-%s" % recipient.get_id with CriticalSection([key], timeout=60): # Get the case to submit the form against, if any if (isinstance(recipient, CommCareCase) and not handler.force_surveys_to_use_triggered_case): case_id = recipient.get_id else: case_id = reminder.case_id if form.requires_case() and not case_id: logged_subevent.error(MessagingEvent.ERROR_NO_CASE_GIVEN) continue # Close all currently open sessions SQLXFormsSession.close_all_open_sms_sessions( reminder.domain, recipient.get_id) # Start the new session try: session, responses = start_session( reminder.domain, recipient, app, module, form, case_id, case_for_case_submission=handler. force_surveys_to_use_triggered_case) except TouchformsError as e: human_readable_message = e.response_data.get( 'human_readable_message', None) logged_subevent.error( MessagingEvent.ERROR_TOUCHFORMS_ERROR, additional_error_text=human_readable_message) if touchforms_error_is_config_error(e): # Don't reraise the exception because this means there are configuration # issues with the form that need to be fixed continue else: # Reraise the exception so that the framework retries it again later raise except Exception as e: logged_subevent.error( MessagingEvent.ERROR_TOUCHFORMS_ERROR) # Reraise the exception so that the framework retries it again later raise session.survey_incentive = handler.survey_incentive session.workflow = get_workflow(handler) session.reminder_id = reminder._id session.save() reminder.xforms_session_ids.append(session.session_id) logged_subevent.xforms_session = session logged_subevent.save() # Send out first message if len(responses) > 0: message = format_message_list(responses) metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) if verified_number: send_sms_to_verified_number(verified_number, message, metadata) else: send_sms(reminder.domain, recipient, unverified_number, message, metadata) logged_subevent.completed()
def global_keyword_stop(v, text, msg, text_words, open_sessions): SQLXFormsSession.close_all_open_sms_sessions(v.domain, v.owner_id) return True
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers, logged_event): current_event = reminder.current_event if reminder.callback_try_count > 0: # Leaving this as an explicit reminder that all survey related actions now happen # in a different process. Eventually all of this code will be removed when we move # to the new reminders framework. pass else: reminder.xforms_session_ids = [] domain_obj = Domain.get_by_name(reminder.domain, strict=True) # Get the app, module, and form try: form_unique_id = current_event.form_unique_id form = Form.get_form(form_unique_id) app = form.get_app() module = form.get_module() except Exception: logged_event.error(MessagingEvent.ERROR_CANNOT_FIND_FORM) return # Start a touchforms session for each recipient for recipient in recipients: logged_subevent = logged_event.create_subevent( handler, reminder, recipient) verified_number, unverified_number = get_recipient_phone_number( reminder, recipient, verified_numbers) no_verified_number = verified_number is None cant_use_unverified_number = (unverified_number is None or form_requires_input(form)) if no_verified_number and cant_use_unverified_number: logged_subevent.error( MessagingEvent.ERROR_NO_TWO_WAY_PHONE_NUMBER) continue if verified_number: pb = PhoneBlacklist.get_by_phone_number_or_none( verified_number.phone_number) else: pb = PhoneBlacklist.get_by_phone_number_or_none( unverified_number) if pb and not pb.send_sms: logged_subevent.error(MessagingEvent.ERROR_PHONE_OPTED_OUT) continue with critical_section_for_smsforms_sessions(recipient.get_id): # Get the case to submit the form against, if any if (is_commcarecase(recipient) and not handler.force_surveys_to_use_triggered_case): case_id = recipient.case_id else: case_id = reminder.case_id if form.requires_case() and not case_id: logged_subevent.error(MessagingEvent.ERROR_NO_CASE_GIVEN) continue # Close all currently open sessions SQLXFormsSession.close_all_open_sms_sessions( reminder.domain, recipient.get_id) # Start the new session try: if current_event.callback_timeout_intervals: if handler.submit_partial_forms: expire_after = sum( current_event.callback_timeout_intervals) reminder_intervals = current_event.callback_timeout_intervals[: -1] else: expire_after = SQLXFormsSession.MAX_SESSION_LENGTH reminder_intervals = current_event.callback_timeout_intervals submit_partially_completed_forms = handler.submit_partial_forms include_case_updates_in_partial_submissions = handler.include_case_side_effects else: expire_after = SQLXFormsSession.MAX_SESSION_LENGTH reminder_intervals = [] submit_partially_completed_forms = False include_case_updates_in_partial_submissions = False session, responses = start_session( SQLXFormsSession.create_session_object( reminder.domain, recipient, verified_number.phone_number if verified_number else unverified_number, app, form, expire_after=expire_after, reminder_intervals=reminder_intervals, submit_partially_completed_forms= submit_partially_completed_forms, include_case_updates_in_partial_submissions= include_case_updates_in_partial_submissions), reminder.domain, recipient, app, module, form, case_id, case_for_case_submission=handler. force_surveys_to_use_triggered_case) except TouchformsError as e: human_readable_message = get_formplayer_exception( reminder.domain, e) logged_subevent.error( MessagingEvent.ERROR_TOUCHFORMS_ERROR, additional_error_text=human_readable_message) if touchforms_error_is_config_error(reminder.domain, e): # Don't reraise the exception because this means there are configuration # issues with the form that need to be fixed continue else: # Reraise the exception so that the framework retries it again later raise except Exception as e: logged_subevent.error( MessagingEvent.ERROR_TOUCHFORMS_ERROR) # Reraise the exception so that the framework retries it again later raise session.survey_incentive = handler.survey_incentive session.workflow = get_workflow(handler) session.reminder_id = reminder._id session.save() reminder.xforms_session_ids.append(session.session_id) logged_subevent.xforms_session = session logged_subevent.save() # Send out first message if len(responses) > 0: message = format_message_list(responses) metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) if verified_number: send_sms_to_verified_number( verified_number, message, metadata, logged_subevent=logged_subevent) else: send_sms(reminder.domain, recipient, unverified_number, message, metadata) logged_subevent.completed()
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers): if reminder.callback_try_count > 0: # Handle timeouts if handler.submit_partial_forms and (reminder.callback_try_count == len(reminder.current_event.callback_timeout_intervals)): # Submit partial form completions for session_id in reminder.xforms_session_ids: submit_unfinished_form(session_id, handler.include_case_side_effects) else: # Resend current question for session_id in reminder.xforms_session_ids: session = get_session_by_session_id(session_id) if session.end_time is None: vn = VerifiedNumber.view("sms/verified_number_by_owner_id", key=session.connection_id, include_docs=True).first() if vn is not None: metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) resp = current_question(session_id) send_sms_to_verified_number(vn, resp.event.text_prompt, metadata) return True else: reminder.xforms_session_ids = [] # Get the app, module, and form try: form_unique_id = reminder.current_event.form_unique_id form = Form.get_form(form_unique_id) app = form.get_app() module = form.get_module() except Exception: raise_error(reminder, ERROR_FORM) return False # Start a touchforms session for each recipient for recipient in recipients: verified_number, unverified_number = get_recipient_phone_number( reminder, recipient, verified_numbers) domain_obj = Domain.get_by_name(reminder.domain, strict=True) no_verified_number = verified_number is None cant_use_unverified_number = (unverified_number is None or not domain_obj.send_to_duplicated_case_numbers or form_requires_input(form)) if no_verified_number and cant_use_unverified_number: if len(recipients) == 1: raise_error(reminder, ERROR_NO_VERIFIED_NUMBER) return False else: continue key = "start-sms-survey-for-contact-%s" % recipient.get_id with CriticalSection([key], timeout=60): # Close all currently open sessions SQLXFormsSession.close_all_open_sms_sessions(reminder.domain, recipient.get_id) # Start the new session if (isinstance(recipient, CommCareCase) and not handler.force_surveys_to_use_triggered_case): case_id = recipient.get_id else: case_id = reminder.case_id session, responses = start_session(reminder.domain, recipient, app, module, form, case_id, case_for_case_submission= handler.force_surveys_to_use_triggered_case) session.survey_incentive = handler.survey_incentive session.workflow = get_workflow(handler) session.reminder_id = reminder._id session.save() reminder.xforms_session_ids.append(session.session_id) # Send out first message if len(responses) > 0: message = format_message_list(responses) metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) if verified_number: result = send_sms_to_verified_number(verified_number, message, metadata) else: result = send_sms(reminder.domain, recipient, unverified_number, message, metadata) if len(recipients) == 1: return result return True
def process_survey_keyword_actions(verified_number, survey_keyword, text, msg): sender = verified_number.owner case = None args = split_args(text, survey_keyword) logged_event = MessagingEvent.create_from_keyword(survey_keyword, sender) # Log a messaging subevent for the incoming message subevent = logged_event.create_subevent_for_single_sms( msg.couch_recipient_doc_type, msg.couch_recipient, completed=True ) add_msg_tags(msg, MessageMetadata(messaging_subevent_id=subevent.pk)) # Close any open sessions even if it's just an sms that we're # responding with. SQLXFormsSession.close_all_open_sms_sessions(verified_number.domain, verified_number.owner_id) if is_commcarecase(sender): case = sender args = args[1:] elif isinstance(sender, CommCareUser): if keyword_uses_form_that_requires_case(survey_keyword): if len(args) > 1: external_id = args[1] case, matches = get_case_by_external_id(verified_number.domain, external_id, sender) if matches == 0: send_keyword_response(verified_number, MSG_CASE_NOT_FOUND, logged_event) logged_event.error(MessagingEvent.ERROR_CASE_EXTERNAL_ID_NOT_FOUND) return elif matches > 1: send_keyword_response(verified_number, MSG_MULTIPLE_CASES_FOUND, logged_event) logged_event.error(MessagingEvent.ERROR_MULTIPLE_CASES_WITH_EXTERNAL_ID_FOUND) return else: send_keyword_response(verified_number, MSG_MISSING_EXTERNAL_ID, logged_event) logged_event.error(MessagingEvent.ERROR_NO_EXTERNAL_ID_GIVEN) return args = args[2:] else: args = args[1:] def cmp_fcn(a1, a2): a1_ss = (a1.action == KeywordAction.ACTION_STRUCTURED_SMS) a2_ss = (a2.action == KeywordAction.ACTION_STRUCTURED_SMS) if a1_ss and a2_ss: return 0 elif a1_ss: return -1 elif a2_ss: return 1 else: return 0 if case: subevent.case_id = case.case_id subevent.save() # Process structured sms actions first actions = sorted(survey_keyword.keywordaction_set.all(), cmp=cmp_fcn) for survey_keyword_action in actions: if survey_keyword_action.recipient == KeywordAction.RECIPIENT_SENDER: contact = sender elif survey_keyword_action.recipient == KeywordAction.RECIPIENT_OWNER: if is_commcarecase(sender): contact = get_wrapped_owner(get_owner_id(sender)) else: contact = None elif survey_keyword_action.recipient == KeywordAction.RECIPIENT_USER_GROUP: try: contact = Group.get(survey_keyword_action.recipient_id) assert contact.doc_type == "Group" assert contact.domain == verified_number.domain except Exception: contact = None else: contact = None if contact is None: continue # contact can be either a user, case, group, or location if survey_keyword_action.action in (KeywordAction.ACTION_SMS, KeywordAction.ACTION_SMS_SURVEY): if isinstance(contact, Group): recipients = list(ScheduleInstance.expand_group(contact)) elif isinstance(contact, SQLLocation): recipients = list(ScheduleInstance.expand_location_ids(contact.domain, [contact.location_id])) else: recipients = [contact] recipient_is_sender = survey_keyword_action.recipient == KeywordAction.RECIPIENT_SENDER if survey_keyword_action.action == KeywordAction.ACTION_SMS: content = SMSContent(message={'*': survey_keyword_action.message_content}) content.set_context(case=case) elif survey_keyword_action.action == KeywordAction.ACTION_SMS_SURVEY: content = SMSSurveyContent( form_unique_id=survey_keyword_action.form_unique_id, expire_after=SQLXFormsSession.MAX_SESSION_LENGTH, ) content.set_context( case=case, critical_section_already_acquired=recipient_is_sender, ) else: raise ValueError("Unexpected action %s" % survey_keyword_action.action) for recipient in recipients: phone_entry = verified_number if recipient_is_sender else None content.send(recipient, logged_event, phone_entry=phone_entry) elif survey_keyword_action.action == KeywordAction.ACTION_STRUCTURED_SMS: res = handle_structured_sms(survey_keyword, survey_keyword_action, sender, verified_number, text, send_response=True, msg=msg, case=case, text_args=args, logged_event=logged_event) if not res: # If the structured sms processing wasn't successful, don't # process any of the other actions return logged_event.completed()