Esempio n. 1
0
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
Esempio n. 2
0
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]))
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
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
Esempio n. 8
0
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