def global_keyword_start(v, text, msg, text_words, open_sessions): from corehq.apps.reminders.models import SurveyKeyword outbound_metadata = MessageMetadata(workflow=WORKFLOW_KEYWORD, ) if len(text_words) > 1: keyword = text_words[1] sk = SurveyKeyword.get_keyword(v.domain, keyword) if sk: if not contact_can_use_keyword(v, sk): return False process_survey_keyword_actions(v, sk, text[6:].strip(), msg) else: message = get_message(MSG_KEYWORD_NOT_FOUND, v, (keyword, )) send_sms_to_verified_number(v, message, metadata=outbound_metadata) else: message = get_message(MSG_START_KEYWORD_USAGE, v, (text_words[0], )) send_sms_to_verified_number(v, message, metadata=outbound_metadata) return True
def add_keyword(request, domain, keyword_id=None): if keyword_id is None: s = SurveyKeyword(domain = domain) else: s = SurveyKeyword.get(keyword_id) context = { "domain" : domain, "form_list" : get_form_list(domain), "errors" : [], "keyword" : s } if request.method == "GET": return render_to_response(request, "reminders/partial/add_keyword.html", context) else: keyword = request.POST.get("keyword", None) form_unique_id = request.POST.get("survey", None) if keyword is not None: keyword = keyword.strip() s.keyword = keyword s.form_unique_id = form_unique_id errors = [] if keyword is None or keyword == "": errors.append("Please enter a keyword.") if form_unique_id is None: errors.append("Please create a form first, and then add a keyword for it.") duplicate_entry = SurveyKeyword.get_keyword(domain, keyword) if duplicate_entry is not None and keyword_id != duplicate_entry._id: errors.append("Keyword already exists.") if len(errors) > 0: context["errors"] = errors return render_to_response(request, "reminders/partial/add_keyword.html", context) else: s.save() return HttpResponseRedirect(reverse("manage_surveys", args=[domain]))
def global_keyword_start(v, text, msg, text_words, open_sessions): from corehq.apps.reminders.models import SurveyKeyword outbound_metadata = MessageMetadata( workflow=WORKFLOW_KEYWORD, ) if len(text_words) > 1: keyword = text_words[1] sk = SurveyKeyword.get_keyword(v.domain, keyword) if sk: if not contact_can_use_keyword(v, sk): return False process_survey_keyword_actions(v, sk, text[6:].strip(), msg) else: message = get_message(MSG_KEYWORD_NOT_FOUND, v, (keyword,)) send_sms_to_verified_number(v, message, metadata=outbound_metadata) else: message = get_message(MSG_START_KEYWORD_USAGE, v, (text_words[0],)) send_sms_to_verified_number(v, message, metadata=outbound_metadata) return True
def form_session_handler(v, text): # Circular Import from corehq.apps.reminders.models import SurveyKeyword, FORM_TYPE_ONE_BY_ONE # Handle incoming sms session = XFormsSession.view( "smsforms/open_sms_sessions_by_connection", key=[v.domain, v.owner_id], include_docs=True ).one() text_words = text.upper().split() # Respond to "#START <keyword>" command if len(text_words) > 0 and text_words[0] == "#START": if len(text_words) > 1: sk = SurveyKeyword.get_keyword(v.domain, text_words[1]) if sk is not None and sk.form_type == FORM_TYPE_ONE_BY_ONE: if session is not None: session.end(False) session.save() start_session_from_keyword(sk, v) else: send_sms_to_verified_number(v, "Survey '" + text_words[1] + "' not found.") else: send_sms_to_verified_number(v, "Usage: #START <keyword>") # Respond to "#STOP" keyword elif len(text_words) > 0 and text_words[0] == "#STOP": if session is not None: session.end(False) session.save() # Respond to "#CURRENT" keyword elif len(text_words) > 0 and text_words[0] == "#CURRENT": if session is not None: resp = current_question(session.session_id) send_sms_to_verified_number(v, resp.event.text_prompt) # Respond to unknown command elif len(text_words) > 0 and text_words[0][0] == "#": send_sms_to_verified_number(v, "Unknown command '" + text_words[0] + "'") # If there's an open session, treat the inbound text as the answer to the next question elif session is not None: resp = current_question(session.session_id) event = resp.event valid, text, error_msg = validate_answer(event, text) if valid: responses = _get_responses(v.domain, v.owner_id, text) if len(responses) > 0: response_text = format_message_list(responses) send_sms_to_verified_number(v, response_text) else: send_sms_to_verified_number(v, error_msg + event.text_prompt) # Try to match the text against a keyword to start a survey elif len(text_words) > 0: sk = SurveyKeyword.get_keyword(v.domain, text_words[0]) if sk is not None and sk.form_type == FORM_TYPE_ONE_BY_ONE: start_session_from_keyword(sk, v) # TODO should clarify what scenarios this handler actually handles. i.e., # should the error responses instead be handler by some generic error/fallback # handler return True
def sms_keyword_handler(v, text, msg=None): from corehq.apps.reminders.models import SurveyKeyword text = text.strip() if text == "": return False sessions = XFormsSession.get_all_open_sms_sessions(v.domain, v.owner_id) any_session_open = len(sessions) > 0 text_words = text.upper().split() if text.startswith("#"): if len(text_words) > 0 and text_words[0] == "#START": # Respond to "#START <keyword>" command if len(text_words) > 1: sk = SurveyKeyword.get_keyword(v.domain, text_words[1]) if sk is not None: if len(sk.initiator_doc_type_filter) > 0 and v.owner_doc_type not in sk.initiator_doc_type_filter: # The contact type is not allowed to invoke this keyword return False process_survey_keyword_actions(v, sk, text[6:].strip(), msg=msg) else: send_sms_to_verified_number( v, "Keyword not found: '%s'." % text_words[1], workflow=WORKFLOW_KEYWORD ) else: send_sms_to_verified_number(v, "Usage: #START <keyword>", workflow=WORKFLOW_KEYWORD) elif len(text_words) > 0 and text_words[0] == "#STOP": # Respond to "#STOP" keyword XFormsSession.close_all_open_sms_sessions(v.domain, v.owner_id) elif len(text_words) > 0 and text_words[0] == "#CURRENT": # Respond to "#CURRENT" keyword if len(sessions) == 1: resp = current_question(sessions[0].session_id) send_sms_to_verified_number( v, resp.event.text_prompt, workflow=sessions[0].workflow, reminder_id=sessions[0].reminder_id, xforms_session_couch_id=sessions[0]._id, ) else: # Response to unknown command send_sms_to_verified_number(v, "Unknown command: '%s'" % text_words[0]) if msg is not None: msg.workflow = WORKFLOW_KEYWORD msg.save() return True else: for survey_keyword in SurveyKeyword.get_all(v.domain): if survey_keyword.delimiter is not None: args = text.split(survey_keyword.delimiter) else: args = text.split() keyword = args[0].strip().upper() if keyword == survey_keyword.keyword.upper(): if any_session_open and not survey_keyword.override_open_sessions: # We don't want to override any open sessions, so just pass and let the form session handler handle the message return False elif ( len(survey_keyword.initiator_doc_type_filter) > 0 and v.owner_doc_type not in survey_keyword.initiator_doc_type_filter ): # The contact type is not allowed to invoke this keyword return False else: process_survey_keyword_actions(v, survey_keyword, text, msg=msg) if msg is not None: msg.workflow = WORKFLOW_KEYWORD msg.save() return True # No keywords matched, so pass the message onto the next handler return False
def form_session_handler(v, text): # Circular Import from corehq.apps.reminders.models import SurveyKeyword # Handle incoming sms session = XFormsSession.view("smsforms/open_sms_sessions_by_connection", key=[v.domain, v.owner_id], include_docs=True).one() text_words = text.upper().split() # Respond to "#START <keyword>" command if len(text_words) > 0 and text_words[0] == "#START": if len(text_words) > 1: sk = SurveyKeyword.get_keyword(v.domain, text_words[1]) if sk is not None: if session is not None: session.end(False) session.save() start_session_from_keyword(sk, v) else: send_sms_to_verified_number(v, "Survey '" + text_words[1] + "' not found.") else: send_sms_to_verified_number(v, "Usage: #START <keyword>") # Respond to "#STOP" keyword elif len(text_words) > 0 and text_words[0] == "#STOP": if session is not None: session.end(False) session.save() # Respond to "#CURRENT" keyword elif len(text_words) > 0 and text_words[0] == "#CURRENT": if session is not None: resp = current_question(session.session_id) send_sms_to_verified_number(v, resp.event.text_prompt) # Respond to unknown command elif len(text_words) > 0 and text_words[0][0] == "#": send_sms_to_verified_number(v, "Unknown command '" + text_words[0] + "'") # If there's an open session, treat the inbound text as the answer to the next question elif session is not None: resp = current_question(session.session_id) event = resp.event valid = False text = text.strip() upper_text = text.upper() # Validate select if event.datatype == "select": # Try to match on phrase (i.e., "Yes" or "No") choices = format_choices(event._dict["choices"]) if upper_text in choices: text = str(choices[upper_text]) valid = True else: try: answer = int(text) if answer >= 1 and answer <= len(event._dict["choices"]): valid = True except ValueError: pass # Validate multiselect elif event.datatype == "multiselect": choices = format_choices(event._dict["choices"]) max_index = len(event._dict["choices"]) proposed_answers = text.split() final_answers = {} try: if event._dict.get("required", True): assert len(proposed_answers) > 0 for answer in proposed_answers: upper_answer = answer.upper() if upper_answer in choices: final_answers[str(choices[upper_answer])] = "" else: int_answer = int(answer) assert int_answer >= 1 and int_answer <= max_index final_answers[str(int_answer)] = "" text = " ".join(final_answers.keys()) valid = True except Exception: pass # Validate int elif event.datatype == "int": try: int(text) valid = True except ValueError: pass # Validate float elif event.datatype == "float": try: float(text) valid = True except ValueError: pass # Validate longint elif event.datatype == "longint": try: long(text) valid = True except ValueError: pass # Validate date (Format: YYYYMMDD) elif event.datatype == "date": try: assert len(text) == 8 int(text) text = text[0:4] + "-" + text[4:6] + "-" + text[6:] parse(text) valid = True except Exception: pass # Validate time (Format: HHMM, 24-hour) elif event.datatype == "time": try: assert len(text) == 4 hour = int(text[0:2]) minute = int(text[2:]) assert hour >= 0 and hour <= 23 assert minute >= 0 and minute <= 59 text = "%s:%s" % (hour, minute) valid = True except Exception: pass # Other question types pass else: valid = True if valid: responses = _get_responses(v.domain, v.owner_id, text) if len(responses) > 0: response_text = format_message_list(responses) send_sms_to_verified_number(v, response_text) else: error_msg = "Invalid Response. " + event.text_prompt send_sms_to_verified_number(v, error_msg) # Try to match the text against a keyword to start a survey elif len(text_words) > 0: sk = SurveyKeyword.get_keyword(v.domain, text_words[0]) if sk is not None: start_session_from_keyword(sk, v) # TODO should clarify what scenarios this handler actually handles. i.e., # should the error responses instead be handler by some generic error/fallback # handler return True
def form_session_handler(v, text): # Circular Import from corehq.apps.reminders.models import SurveyKeyword, FORM_TYPE_ONE_BY_ONE # Handle incoming sms session = XFormsSession.view("smsforms/open_sms_sessions_by_connection", key=[v.domain, v.owner_id], include_docs=True).one() text_words = text.upper().split() # Respond to "#START <keyword>" command if len(text_words) > 0 and text_words[0] == "#START": if len(text_words) > 1: sk = SurveyKeyword.get_keyword(v.domain, text_words[1]) if sk is not None and sk.form_type == FORM_TYPE_ONE_BY_ONE: if session is not None: session.end(False) session.save() start_session_from_keyword(sk, v) else: send_sms_to_verified_number( v, "Survey '" + text_words[1] + "' not found.") else: send_sms_to_verified_number(v, "Usage: #START <keyword>") # Respond to "#STOP" keyword elif len(text_words) > 0 and text_words[0] == "#STOP": if session is not None: session.end(False) session.save() # Respond to "#CURRENT" keyword elif len(text_words) > 0 and text_words[0] == "#CURRENT": if session is not None: resp = current_question(session.session_id) send_sms_to_verified_number(v, resp.event.text_prompt) # Respond to unknown command elif len(text_words) > 0 and text_words[0][0] == "#": send_sms_to_verified_number(v, "Unknown command '" + text_words[0] + "'") # If there's an open session, treat the inbound text as the answer to the next question elif session is not None: resp = current_question(session.session_id) event = resp.event valid, text, error_msg = validate_answer(event, text) if valid: responses = _get_responses(v.domain, v.owner_id, text) if len(responses) > 0: response_text = format_message_list(responses) send_sms_to_verified_number(v, response_text) else: send_sms_to_verified_number(v, error_msg + event.text_prompt) # Try to match the text against a keyword to start a survey elif len(text_words) > 0: sk = SurveyKeyword.get_keyword(v.domain, text_words[0]) if sk is not None and sk.form_type == FORM_TYPE_ONE_BY_ONE: start_session_from_keyword(sk, v) # TODO should clarify what scenarios this handler actually handles. i.e., # should the error responses instead be handler by some generic error/fallback # handler return True
def incoming(phone_number, text, backend_api): phone_without_plus = str(phone_number) if phone_without_plus[0] == "+": phone_without_plus = phone_without_plus[1:] phone_with_plus = "+" + phone_without_plus # Circular Import from corehq.apps.reminders.models import SurveyKeyword v = VerifiedNumber.view("sms/verified_number_by_number", key=phone_without_plus, include_docs=True ).one() # Log message in message log msg = SMSLog( phone_number = phone_with_plus, direction = INCOMING, date = datetime.utcnow(), text = text, backend_api = backend_api ) if v is not None: msg.couch_recipient_doc_type = v.owner_doc_type msg.couch_recipient = v.owner_id msg.domain = v.domain msg.save() # Handle incoming sms if v is not None: session = XFormsSession.view("smsforms/open_sessions_by_connection", key=[v.domain, v.owner_id], include_docs=True).one() text_words = text.upper().split() # Respond to "#START <keyword>" command if len(text_words) > 0 and text_words[0] == "#START": if len(text_words) > 1: sk = SurveyKeyword.get_keyword(v.domain, text_words[1]) if sk is not None: if session is not None: session.end(False) session.save() start_session_from_keyword(sk, v) else: send_sms_to_verified_number(v, "Survey '" + text_words[1] + "' not found.") else: send_sms_to_verified_number(v, "Usage: #START <keyword>") # Respond to "#STOP" keyword elif len(text_words) > 0 and text_words[0] == "#STOP": if session is not None: session.end(False) session.save() # Respond to "#CURRENT" keyword elif len(text_words) > 0 and text_words[0] == "#CURRENT": if session is not None: resp = current_question(session.session_id) send_sms_to_verified_number(v, resp.event.text_prompt) # Respond to unknown command elif len(text_words) > 0 and text_words[0][0] == "#": send_sms_to_verified_number(v, "Unknown command '" + text_words[0] + "'") # If there's an open session, treat the inbound text as the answer to the next question elif session is not None: resp = current_question(session.session_id) event = resp.event valid = False error_msg = None # Validate select questions if event.datatype == "select": try: answer = int(text.strip()) if answer >= 1 and answer <= len(event._dict["choices"]): valid = True except Exception: pass if not valid: error_msg = "Invalid Response. " + event.text_prompt # For now, anything else passes else: valid = True if valid: responses = get_responses(msg) if len(responses) > 0: response_text = format_message_list(responses) send_sms_to_verified_number(v, response_text) else: send_sms_to_verified_number(v, error_msg) # Try to match the text against a keyword to start a survey elif len(text_words) > 0: sk = SurveyKeyword.get_keyword(v.domain, text_words[0]) if sk is not None: start_session_from_keyword(sk, v) else: #TODO: Registration via SMS pass