def _get_responses(domain, recipient, text, yield_responses=False, session_id=None, update_timestamp=True): """ Try to process this message like a session-based submission against an xform. Returns a list of responses if there are any. """ session = None if session_id is not None: if update_timestamp: # The IVR workflow passes the session id session = XFormsSession.latest_by_session_id(session_id) else: # The SMS workflow grabs the open sms session session = XFormsSession.get_open_sms_session(domain, recipient) if session is not None: session_id = session.session_id if update_timestamp and session is not None: session.modified_time = datetime.utcnow() session.save() if session_id is not None: # TODO auth if yield_responses: return list(tfsms.next_responses(session_id, text, auth=None)) else: return _responses_to_text(tfsms.next_responses(session_id, text, auth=None))
def _get_responses(domain, recipient, text, yield_responses=False, session_id=None, update_timestamp=True): """ Try to process this message like a session-based submission against an xform. Returns a list of responses if there are any. """ session = None if session_id is not None: if update_timestamp: # The IVR workflow passes the session id session = SQLXFormsSession.by_session_id(session_id) else: # The SMS workflow grabs the open sms session session = SQLXFormsSession.get_open_sms_session(domain, recipient) if session is not None: session_id = session.session_id if update_timestamp and session is not None: session.modified_time = datetime.utcnow() session.save() if session_id is not None: # TODO auth if yield_responses: return list(tfsms.next_responses(session_id, text, auth=None)) else: return _responses_to_text( tfsms.next_responses(session_id, text, auth=None))
def _get_responses(domain, recipient, text, yield_responses=False, session_id=None): """ Try to process this message like a session-based submission against an xform. Returns a list of responses if there are any. """ # assumes couch_recipient is the connection_id if session_id is not None: session = XFormsSession.latest_by_session_id(session_id) else: # The IVR workflow passes the session id, the SMS workflow grabs the open sms session session = XFormsSession.view( "smsforms/open_sms_sessions_by_connection", key=[domain, recipient], include_docs=True).one() if session: session.modified_time = datetime.utcnow() session.save() # TODO auth if yield_responses: return list( tfsms.next_responses(session.session_id, text, auth=None)) else: return _responses_to_text( tfsms.next_responses(session.session_id, text, auth=None))
def get_responses(domain, session_id, text): """ Try to process this message like a session-based submission against an xform. Returns a list of responses if there are any. """ return list(tfsms.next_responses(session_id, text))
def _try_process_as_session_form(self, msg): """ Try to process this message like a session-based submission against an xform. Returns True if the message matches and was processed. """ logger.debug('Attempting to process message as SESSION FORM') # check if this connection is in a form session: session = self.get_session(msg) trigger = self.get_trigger_keyword(msg) if not trigger and session is None: logger.debug('Not a session form (no session or trigger kw found') # catch if they reply to the last text from a previous session; we don't # want to send them a confusing error message. recent_sess = self.get_recent_session(msg) lockout = settings.SMSFORMS_POSTSESSION_LOCKOUT \ if hasattr(settings, 'SMSFORMS_POSTSESSION_LOCKOUT') \ else None if recent_sess and lockout and datetime.utcnow() < recent_sess.end_time + lockout: # if no other handlers handle this message, it will be swallowed (in the default phase) self.swallow = True return False elif trigger and session: # mark old session as 'cancelled' and follow process for creating a new one logger.debug('Found trigger kw and stale session. Ending old session and starting fresh.') session.cancel() session = None if session: logger.debug('Found an existing session, attempting to answer question with message content: %s' % msg.text) last_response = api.current_question(session.session_id) ans, error_msg = _pre_validate_answer(msg.text, last_response) # we need the last response to figure out what question type this is. if error_msg: msg.respond("%s for \"%s\"" % (error_msg, session.question_to_prompt(last_response))) return True responses = tfsms.next_responses(session.session_id, ans, auth=None) elif trigger: logger.debug('Found trigger keyword. Starting a new session') session, responses = self._start_session(msg, trigger) else: raise Exception("This is not a legal state. Some of our preconditions failed.") [msg.respond(session.question_to_prompt(resp)) for resp in responses if resp.text_prompt] logger.debug('Completed processing message as part of SESSION FORM') return True
def _get_responses(domain, recipient, text, yield_responses=False, session_id=None): """ Try to process this message like a session-based submission against an xform. Returns a list of responses if there are any. """ # assumes couch_recipient is the connection_id if session_id is not None: session = XFormsSession.latest_by_session_id(session_id) else: # The IVR workflow passes the session id, the SMS workflow grabs the open sms session session = XFormsSession.view("smsforms/open_sms_sessions_by_connection", key=[domain, recipient], include_docs=True).one() if session: session.modified_time = datetime.utcnow() session.save() # TODO auth if yield_responses: return list(tfsms.next_responses(session.session_id, text, auth=None)) else: return _responses_to_text(tfsms.next_responses(session.session_id, text, auth=None))
def get_responses(msg): """ Try to process this message like a session-based submission against an xform. Returns a list of responses if there are any. """ # assumes couch_recipient is the connection_id session = XFormsSession.view("smsforms/open_sessions_by_connection", key=[msg.domain, msg.couch_recipient], include_docs=True).one() if session: session.modified_time = datetime.utcnow() session.save() # TODO auth return _responses_to_text(tfsms.next_responses(session.session_id, msg.text, auth=None))
def _try_process_as_session_form(self, msg): """ Try to process this message like a session-based submission against an xform. Returns True if the message matches and was processed. """ logger.debug('Attempting to process message as SESSION FORM') # check if this connection is in a form session: session = self.get_session(msg) trigger = self.get_trigger_keyword(msg) if not trigger and session is None: logger.debug('Not a session form (no session or trigger kw found') return elif trigger and session: # mark old session as 'cancelled' and follow process for creating a new one logger.debug('Found trigger kw and stale session. Ending old session and starting fresh.') session.cancel() session = None if session: logger.debug('Found an existing session, attempting to answer question with message content: %s' % msg.text) last_response = api.current_question(session.session_id) ans, error_msg = _pre_validate_answer(msg.text, last_response) # we need the last response to figure out what question type this is. if error_msg: msg.respond("%s for \"%s\"" % (error_msg, _prompt(last_response))) return True responses = tfsms.next_responses(session.session_id, ans, auth=None) elif trigger: logger.debug('Found trigger keyword. Starting a new session') session, responses = self._start_session(msg, trigger) else: raise Exception("This is not a legal state. Some of our preconditions failed.") [msg.respond(_prompt(resp)) for resp in responses if resp.text_prompt] logger.debug('Completed processing message as part of SESSION FORM') return True
def _try_process_as_whole_form(self, msg): """ Try to process this message like an entire submission against an xform. Returns True if the message matches and was processed. """ def _match_to_whole_form(msg): # for short term, the syntax for whole forms is any message with # more than one word in it. First word is taken as keyword and # the rest as answers instead of just the keyword (for interactive # form entry). This should be smarter, later. text = msg.text.strip() if text: words = text.strip().split() if len(words) > 1: return self.get_trigger_keyword(msg) return None def _break_into_answers(msg): # TODO: brittle and not fully featured return map(lambda ans: _tf_format(ans)[0], re.split(settings.ANSWER_DELIMITER_RE, msg.text.strip())[1:]) trigger = _match_to_whole_form(msg) if not trigger: return # close any existing sessions _close_open_sessions(msg.connection) # start the form session session, responses = self._start_session(msg, trigger) assert len(responses) > 0, "there should be at least 1 response" if responses[0].is_error: # if the initial session fails, just close the session immediately # and return the error session.end() msg.respond(responses[0].error) return True # loop through answers current_question = list(responses)[-1] answers = _break_into_answers(msg) for i, answer in enumerate(answers): logging.debug('Processing answer: %s' % answer) # Attempt to clean and validate given answer before sending to TF answer, validation_error_msg = _pre_validate_answer(answer, current_question) if validation_error_msg: return _respond_and_end("%s for \"%s\"" % (validation_error_msg, session.question_to_prompt(current_question)), msg, session) responses = tfsms.next_responses(session.session_id, answer) current_question = list(responses)[-1] # get the last touchforms response object so that we can validate our answer # instead of relying on touchforms and getting back a less than useful error. if _handle_xformresponse_error(current_question, msg, session, self.router): return True if i+1 != len(answers) and current_question.event and \ current_question.event.type == 'form-complete': logger.debug('Form completed but their are extra answers. Silently dropping extras! %s' % (", ".join([str(a) for a in answers[i-1:]]))) logger.warn('Silently dropping extra answer on Full Form session! Message:%s, connection: %s' % (msg.text, msg.connection)) # We're done here and the session has been ended (in _next()). # TODO: Should we return a response to the user warning them there are extras? break # play through the remaining questions at the end of the form # and if they are all optional, answer them with blanks and # finish. session = XFormsSession.objects.get(pk=session.pk) if not session.ended: # and trigger.allow_incomplete: while not session.ended and responses: responses = tfsms.next_responses(session.session_id, "") current_question = list(responses)[-1] # if any of the remaining items complain about an empty # answer, send the response if _handle_xformresponse_error(current_question, msg, session, self.router): return True session = XFormsSession.objects.get(pk=session.pk) session = XFormsSession.objects.get(pk=session.pk) if not session.ended: msg.respond("Incomplete form! The first unanswered question is '%s'." % session.question_to_prompt(current_question)) # for now, manually end the session to avoid # confusing the session-based engine session.end() return True