Exemplo n.º 1
0
 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 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']
Exemplo n.º 3
0
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("")
Exemplo n.º 4
0
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("")
Exemplo n.º 5
0
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("")
Exemplo n.º 6
0
 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
Exemplo n.º 7
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
Exemplo n.º 8
0
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)]
Exemplo n.º 9
0
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)]
Exemplo n.º 10
0
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)]
Exemplo n.º 11
0
    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()
Exemplo n.º 12
0
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("")
Exemplo n.º 13
0
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("")