def get_call_couch_ids(self): result = CallLog.view( 'sms/by_domain', include_docs=False, reduce=False, ).all() return [row['id'] for row in result if row['key'][1] == 'CallLog']
def ivr_finished(request): # Retrieve all parameters status = request.POST.get("status", None) start_time = request.POST.get("start_time", None) caller_id = request.POST.get("caller_id", None) phone_no = request.POST.get("phone_no", None) sid = request.POST.get("sid", "") duration = request.POST.get("duration", None) ringing_time = request.POST.get("ringing_time", None) status_details = request.POST.get("status_details", None) gateway_session_id = "KOOKOO-" + sid with CriticalSection([gateway_session_id]): call_log_entry = CallLog.view("sms/call_by_session", startkey=[gateway_session_id, {}], endkey=[gateway_session_id], descending=True, include_docs=True, limit=1).one() if call_log_entry is not None: try: duration = int(duration) except Exception: duration = None call_log_entry.answered = (status == "answered") call_log_entry.duration = duration call_log_entry.save() return HttpResponse("")
def ivr_finished(request): """ Kookoo invokes this view after a call is finished (whether answered or not) with status and some statistics. Point Kookoo's 'callback_url' parameter here. """ # Retrieve all parameters status = request.POST.get("status", None) start_time = request.POST.get("start_time", None) caller_id = request.POST.get("caller_id", None) phone_no = request.POST.get("phone_no", None) sid = request.POST.get("sid", "") duration = request.POST.get("duration", None) ringing_time = request.POST.get("ringing_time", None) status_details = request.POST.get("status_details", None) gateway_session_id = "KOOKOO-" + sid with CriticalSection([gateway_session_id], timeout=300): call_log_entry = CallLog.view("sms/call_by_session", startkey=[gateway_session_id, {}], endkey=[gateway_session_id], descending=True, include_docs=True, limit=1).one() if call_log_entry is not None: try: duration = int(duration) except Exception: duration = None call_log_entry.answered = (status == "answered") call_log_entry.duration = duration call_log_entry.save() return HttpResponse("")
def ivr_finished(request): # Retrieve all parameters status = request.POST.get("status", None) start_time = request.POST.get("start_time", None) caller_id = request.POST.get("caller_id", None) phone_no = request.POST.get("phone_no", None) sid = request.POST.get("sid", "") duration = request.POST.get("duration", None) ringing_time = request.POST.get("ringing_time", None) status_details = request.POST.get("status_details", None) gateway_session_id = "KOOKOO-" + sid call_log_entry = CallLog.view("sms/call_by_session", startkey=[gateway_session_id, {}], endkey=[gateway_session_id], descending=True, include_docs=True, limit=1).one() if call_log_entry is not None: try: duration = int(duration) except Exception: duration = None call_log_entry.answered = (status == "answered") call_log_entry.duration = duration call_log_entry.save() return HttpResponse("")
def getCallLogCount(self): result = CallLog.view( 'sms/by_domain', startkey=[self.domain, 'CallLog'], endkey=[self.domain, 'CallLog', {}], include_docs=False, reduce=True, ).all() if result: return result[0]['value'] return 0
def get_last_outbound_call(self, contact): # Not clear why this should be necessary, but without it the latest # call may not be returned sleep(0.25) call = CallLog.view("sms/by_recipient", startkey=[contact.doc_type, contact._id, "CallLog", "O", {}], endkey=[contact.doc_type, contact._id, "CallLog", "O"], descending=True, include_docs=True, reduce=False, ).first() return call
def get_ids(start_date=None): result = CallLog.view( 'sms/call_by_session', include_docs=False, ).all() def include_row(row): if start_date: try: date = parse(row['key'][1]).replace(tzinfo=None) except: return False return date >= start_date return True return [row['id'] for row in result if include_row(row)]
def get_ids(start_date=None, timezone=None): result = CallLog.view( 'sms/call_by_session', include_docs=False, ).all() def include_row(row): if start_date: date = row['key'][1] if date: date = parse(date).replace(tzinfo=None) date = get_naive_user_datetime(date, timezone=timezone) return date >= start_date else: return False return True return [row['id'] for row in result if include_row(row)]
def deleteAllLogs(self): for smslog in SMSLog.view( 'sms/by_domain', startkey=[self.domain, 'SMSLog'], endkey=[self.domain, 'SMSLog', {}], include_docs=True, reduce=False, ).all(): smslog.delete() for callog in CallLog.view( 'sms/by_domain', startkey=[self.domain, 'CallLog'], endkey=[self.domain, 'CallLog', {}], include_docs=True, reduce=False, ).all(): callog.delete() for obj in LastReadMessage.view( 'sms/last_read_message', startkey=['by_anyone', self.domain], endkey=['by_anyone', self.domain, {}], include_docs=True, ).all(): obj.delete() for obj in ExpectedCallbackEventLog.view( 'sms/expected_callback_event', startkey=[self.domain], endkey=[self.domain, {}], include_docs=True, ).all(): obj.delete() SMS.objects.filter(domain=self.domain).delete() Call.objects.filter(domain=self.domain).delete() MessagingSubEvent.objects.filter(parent__domain=self.domain).delete() MessagingEvent.objects.filter(domain=self.domain).delete() SQLLastReadMessage.objects.filter(domain=self.domain).delete() ExpectedCallback.objects.filter(domain=self.domain).delete()
def incoming(phone_number, backend_module, gateway_session_id, ivr_event, input_data=None): # Look up the call if one already exists call_log_entry = CallLog.view("sms/call_by_session", startkey=[gateway_session_id, {}], endkey=[gateway_session_id], descending=True, include_docs=True, limit=1).one() answer_is_valid = False # This will be set to True if IVR validation passes error_occurred = False # This will be set to False if touchforms validation passes (i.e., no form constraints fail) if call_log_entry is not None and backend_module: if ivr_event == IVR_EVENT_NEW_CALL and call_log_entry.use_precached_first_response: return HttpResponse(call_log_entry.first_response) form = Form.get_form(call_log_entry.form_unique_id) app = form.get_app() module = form.get_module() recipient = call_log_entry.recipient if ivr_event == IVR_EVENT_NEW_CALL: case_id = call_log_entry.case_id case_for_case_submission = call_log_entry.case_for_case_submission session, responses = start_session(recipient.domain, recipient, app, module, form, case_id, yield_responses=True, session_type=XFORMS_SESSION_IVR, case_for_case_submission=case_for_case_submission) call_log_entry.xforms_session_id = session.session_id elif ivr_event == IVR_EVENT_INPUT: if call_log_entry.xforms_session_id is not None: current_q = current_question(call_log_entry.xforms_session_id) if validate_answer(input_data, current_q): answer_is_valid = True responses = _get_responses(recipient.domain, recipient._id, input_data, yield_responses=True, session_id=call_log_entry.xforms_session_id) else: call_log_entry.current_question_retry_count += 1 responses = [current_q] else: responses = [] else: responses = [] ivr_responses = [] hang_up = False for response in responses: if response.is_error: error_occurred = True call_log_entry.current_question_retry_count += 1 if response.text_prompt is None: ivr_responses = [] break else: ivr_responses.append(format_ivr_response(response.text_prompt, app)) elif response.event.type == "question": ivr_responses.append(format_ivr_response(response.event.caption, app)) elif response.event.type == "form-complete": hang_up = True if answer_is_valid and not error_occurred: call_log_entry.current_question_retry_count = 0 if call_log_entry.max_question_retries is not None and call_log_entry.current_question_retry_count > call_log_entry.max_question_retries: # Force hang-up ivr_responses = [] if len(ivr_responses) == 0: hang_up = True input_length = None if hang_up: if call_log_entry.xforms_session_id is not None: # Process disconnect session = get_session_by_session_id(call_log_entry.xforms_session_id) if session.end_time is None: if call_log_entry.submit_partial_form: submit_unfinished_form(session.session_id, call_log_entry.include_case_side_effects) else: session.end(completed=False) session.save() else: # Set input_length to let the ivr gateway know how many digits we need to collect. # Have to get the current question again, since the last XFormsResponse in responses # may not have an event if it was a response to a constraint error. if error_occurred: current_q = current_question(call_log_entry.xforms_session_id) else: current_q = responses[-1] input_length = get_input_length(current_q) call_log_entry.save() return HttpResponse(backend_module.get_http_response_string(gateway_session_id, ivr_responses, collect_input=(not hang_up), hang_up=hang_up, input_length=input_length)) # If not processed, just log the call if call_log_entry: # No need to log, already exists return HttpResponse("") cleaned_number = phone_number if cleaned_number is not None and len(cleaned_number) > 0 and cleaned_number[0] == "+": cleaned_number = cleaned_number[1:] # Try to look up the verified number entry v = VerifiedNumber.view("sms/verified_number_by_number", key=cleaned_number, include_docs=True ).one() # If none was found, try to match only the last digits of numbers in the database if v is None: v = VerifiedNumber.view("sms/verified_number_by_suffix", key=cleaned_number, include_docs=True ).one() # Save the call entry msg = CallLog( phone_number=cleaned_number, direction=INCOMING, date=datetime.utcnow(), backend_api=backend_module.API_ID if backend_module else None, gateway_session_id=gateway_session_id, ) if v is not None: msg.domain = v.domain msg.couch_recipient_doc_type = v.owner_doc_type msg.couch_recipient = v.owner_id msg.save() return HttpResponse("")
def incoming(phone_number, backend_module, gateway_session_id, ivr_event, input_data=None): # Look up the call if one already exists call_log_entry = CallLog.view("sms/call_by_session", startkey=[gateway_session_id, {}], endkey=[gateway_session_id], descending=True, include_docs=True, limit=1).one() answer_is_valid = False # This will be set to True if IVR validation passes error_occurred = False # This will be set to False if touchforms validation passes (i.e., no form constraints fail) if call_log_entry is not None and backend_module: if ivr_event == IVR_EVENT_NEW_CALL and call_log_entry.use_precached_first_response: return HttpResponse(call_log_entry.first_response) form = Form.get_form(call_log_entry.form_unique_id) app = form.get_app() module = form.get_module() recipient = call_log_entry.recipient if ivr_event == IVR_EVENT_NEW_CALL: case_id = call_log_entry.case_id case_for_case_submission = call_log_entry.case_for_case_submission session, responses = start_session( recipient.domain, recipient, app, module, form, case_id, yield_responses=True, session_type=XFORMS_SESSION_IVR, case_for_case_submission=case_for_case_submission) call_log_entry.xforms_session_id = session.session_id elif ivr_event == IVR_EVENT_INPUT: if call_log_entry.xforms_session_id is not None: current_q = current_question(call_log_entry.xforms_session_id) if validate_answer(input_data, current_q): answer_is_valid = True responses = _get_responses( recipient.domain, recipient._id, input_data, yield_responses=True, session_id=call_log_entry.xforms_session_id) else: call_log_entry.current_question_retry_count += 1 responses = [current_q] else: responses = [] else: responses = [] ivr_responses = [] hang_up = False for response in responses: if response.is_error: error_occurred = True call_log_entry.current_question_retry_count += 1 if response.text_prompt is None: ivr_responses = [] break else: ivr_responses.append( format_ivr_response(response.text_prompt, app)) elif response.event.type == "question": ivr_responses.append( format_ivr_response(response.event.caption, app)) elif response.event.type == "form-complete": hang_up = True if answer_is_valid and not error_occurred: call_log_entry.current_question_retry_count = 0 if call_log_entry.max_question_retries is not None and call_log_entry.current_question_retry_count > call_log_entry.max_question_retries: # Force hang-up ivr_responses = [] if len(ivr_responses) == 0: hang_up = True input_length = None if hang_up: if call_log_entry.xforms_session_id is not None: # Process disconnect session = XFormsSession.latest_by_session_id( call_log_entry.xforms_session_id) if session.end_time is None: if call_log_entry.submit_partial_form: submit_unfinished_form( session.session_id, call_log_entry.include_case_side_effects) else: session.end(completed=False) session.save() else: # Set input_length to let the ivr gateway know how many digits we need to collect. # Have to get the current question again, since the last XFormsResponse in responses # may not have an event if it was a response to a constraint error. if error_occurred: current_q = current_question(call_log_entry.xforms_session_id) else: current_q = responses[-1] input_length = get_input_length(current_q) call_log_entry.save() return HttpResponse( backend_module.get_http_response_string( gateway_session_id, ivr_responses, collect_input=(not hang_up), hang_up=hang_up, input_length=input_length)) # If not processed, just log the call if call_log_entry: # No need to log, already exists return HttpResponse("") cleaned_number = phone_number if cleaned_number is not None and len( cleaned_number) > 0 and cleaned_number[0] == "+": cleaned_number = cleaned_number[1:] # Try to look up the verified number entry v = VerifiedNumber.view("sms/verified_number_by_number", key=cleaned_number, include_docs=True).one() # If none was found, try to match only the last digits of numbers in the database if v is None: v = VerifiedNumber.view("sms/verified_number_by_suffix", key=cleaned_number, include_docs=True).one() # Save the call entry msg = CallLog( phone_number=cleaned_number, direction=INCOMING, date=datetime.utcnow(), backend_api=backend_module.API_ID if backend_module else None, gateway_session_id=gateway_session_id, ) if v is not None: msg.domain = v.domain msg.couch_recipient_doc_type = v.owner_doc_type msg.couch_recipient = v.owner_id msg.save() return HttpResponse("")