def testImproperNesting(self): """ bad nesting """ verb = twiml.Gather() self.assertRaises(TwimlException, verb.append, twiml.Gather()) self.assertRaises(TwimlException, verb.append, twiml.Record()) self.assertRaises(TwimlException, verb.append, twiml.Hangup()) self.assertRaises(TwimlException, verb.append, twiml.Redirect()) self.assertRaises(TwimlException, verb.append, twiml.Dial()) self.assertRaises(TwimlException, verb.append, twiml.Conference("")) self.assertRaises(TwimlException, verb.append, twiml.Sms(""))
def PracticeIVR_TreeRoot_New(request): """ will be called if it is practice manager calling and set up was done already update set up option only, we have no msgs on this number """ r = twilio.Response() #practice = PracticeLocation.objects.get(id=request.session['practice_id']) if ('Digits' in request.POST): logger.debug('%s: PracticeIVR_TreeRoot_New digits %s' % ( request.session.session_key, request.POST['Digits'])) digits = request.POST['Digits'] p = re.compile('[0-9#*]$') if (not p.match(digits)): r.append(tts(_('I\'m sorry, I didn\'t understand that.'))) elif (digits == '3'): request.session['ivr2_state'] = 'PracticeIVR_Options_New' request.session.modified = True return PracticeIVR_Options_New(request, r) elif (digits == '*'): pass else: r.append(tts(_('I\'m sorry, I didn\'t understand that.'))) gather = twilio.Gather(finishOnKey='', numDigits=1, timeout=30) r.append(tts(_("Wecome to you voice mail account. Your set up is " "complete. This account does not have mail box."))) gather.append(tts(_('To manage your settings, press 3'))) gather.append(tts(_('To repeat this menu, press star'))) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def getRecording_playRecordingAndConfirmation(request, twilioResponse): gather = twilio.Gather(numDigits=1, finishOnKey='', action=reverse('getRecording')) gather.append(tts(_("You said"))) gather.append(twilio.Play(request.session['ivr_makeRecording_recording'])) gather.append(tts(_('If you wish to record again, please press three.' 'Press one to continue. Press any other key to replay the recording.'))) twilioResponse.append(gather) twilioResponse.append(twilio.Redirect())
def testEmpty(self): """ a gather with nothing inside""" r = Response() r.append(twiml.Gather()) r = self.strip(r) self.assertEquals( r, '<?xml version="1.0" encoding="UTF-8"?><Response><Gather /></Response>' )
def testNestedSayPlayPause(self): """ a gather with a say, play, and pause """ r = Response() g = twiml.Gather() g.append(twiml.Say("Hey")) g.append(twiml.Play("hey.mp3")) g.append(twiml.Pause()) r.append(g) r = self.strip(r) assert_equal(r, '<?xml version="1.0" encoding="UTF-8"?><Response><Gather><Say>Hey</Say><Play>hey.mp3</Play><Pause /></Gather></Response>')
def ProviderIVR_Options(request, internalCall=False): r = twilio.Response() if (not internalCall and request.method == 'POST' and 'Digits' in request.POST): digits = request.POST['Digits'] p = re.compile('[0-9#*]$') if (not p.match(digits)): r.append(tts('I\'m sorry, I didn\'t understand that.')) elif (digits == '1'): # Change name request.session['ivr_call_stack'].append('ProviderIVR_Options') request.session.modified = True event = callEvent(callSID=request.POST['CallSid'], event='F_NCH') return changeName(request) elif (digits == '3'): # Change greeting request.session['ivr_call_stack'].append('ProviderIVR_Options') request.session.modified = True event = callEvent(callSID=request.POST['CallSid'], event='F_GCH') return changeGreeting(request) elif (digits == '5'): # Change pin request.session['ivr_call_stack'].append('ProviderIVR_Options') request.session.modified = True event = callEvent(callSID=request.POST['CallSid'], event='F_PCH') return changePin(request, None, True) elif (digits == '*'): # Repeat menu pass elif (digits == '9'): # Return to the main menu r.append( twilio.Redirect( reverse(request.session['ivr_call_stack'].pop()))) request.session.modified = True return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) else: r.append(tts('I\'m sorry, that wasn\t a valid selection.')) gather = twilio.Gather(finishOnKey='', numDigits=1, action=reverse('ProviderIVR_Options')) gather.append(tts('Options menu')) gather.append(tts('To re-record your name, press 1')) gather.append(tts('To record a new greeting, press 3')) gather.append(tts('To change your pin, press 5')) gather.append(tts('To return to the main menu, press 9')) gather.append(tts('To repeat this menu, press star')) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def improperAppend(self, verb): self.assertRaises(TwimlException, verb.append, twiml.Say("")) self.assertRaises(TwimlException, verb.append, twiml.Gather()) self.assertRaises(TwimlException, verb.append, twiml.Play("")) self.assertRaises(TwimlException, verb.append, twiml.Record()) self.assertRaises(TwimlException, verb.append, twiml.Hangup()) self.assertRaises(TwimlException, verb.append, twiml.Reject()) self.assertRaises(TwimlException, verb.append, twiml.Redirect()) self.assertRaises(TwimlException, verb.append, twiml.Dial()) self.assertRaises(TwimlException, verb.append, twiml.Conference("")) self.assertRaises(TwimlException, verb.append, twiml.Sms("")) self.assertRaises(TwimlException, verb.append, twiml.Pause())
def PracticeIVR_Options_New(request, twilioResponse=None): """ Options Menu to change practice pin, name, greetings """ r = twilioResponse or twilio.Response() gather = twilio.Gather(finishOnKey='', numDigits=1, action=reverse('PracticeIVR_Options_Actions')) gather.append(tts(_('Options menu'))) gather.append(tts(_('To re-record your name, press 1'))) gather.append(tts(_('To record a new closed office greeting, press 3'))) gather.append(tts(_('To record a new greeting while the office is open, press 5'))) gather.append(tts(_('To change your pin, press 7'))) gather.append(tts(_('To return to the main menu, press 9'))) gather.append(tts(_('To repeat this menu, press star'))) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def PracticeIVR_ForwardCall_Vet(request): """ This function is executed on Number nouns within Dial verbs. The idea is to try to determine if it's a human who picked up, or a machine. Alternatively, this gives the called party a chance to send the call to voicemail without the caller knowing they're rejecting the call. """ logger.debug('%s: PracticeIVR_ForwardCall_Vet ' % (request.session.session_key)) r = twilio.Response() # First, find the recording to play callSID = request.POST['CallSid'] # second leg calls have their own callSIDs - may need parentCallSID (log, plog) = _getCallLogOrParent(request) if (request.method == 'POST' and 'Digits' in request.POST): # Connect the calls log.call_connected = True log.save() if plog: plog.call_connected = True plog.save() logger.debug('%s: PracticeIVR_ForwardCall_Vet update parent of logsid %s plogSID %s' % (request.session.session_key, log.callSID, plog.callSID)) event = callEvent(callSID=callSID, event='C_ACC') event.save() return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) caller_spoken_name = log.caller_spoken_name gather = twilio.Gather(numDigits=1, finishOnKey='', action=reverse('PracticeIVR_ForwardCall_Vet')) if('click2call' in request.session): gather.append(tts(_("You have a call from"))) gather.append(twilio.Play(caller_spoken_name)) gather.append(tts(_("Press any key to accept."))) else: gather.append(tts(_("You have an urgent answering service call from"))) gather.append(twilio.Play(caller_spoken_name)) gather.append(tts(_("Press any key to accept."))) r.append(gather) r.append(twilio.Hangup()) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def PracticeIVR_CallerResponse_New(request, twilioResponse=None): """ This function process callers response - set up practice greeting based on practice hours and callgroups and specialties (via create_dynamic_greeting) """ request.session['ivr2_state'] = 'PracticeIVR_CallerResponse_New' practice = PracticeLocation.objects.get(id=request.session['practice_id']) logger.debug('%s: PracticeIVR_CallerResponse_New state %s practice %s' % ( request.session.session_key, request.session['ivr2_state'], practice)) r = twilioResponse or twilio.Response() gather = twilio.Gather(action=reverse('PracticeIVR_CallerResponse_Action'), finishOnKey='', numDigits=1, timeout=60) if (not 'practice_greeting' in request.session): if (practice.is_open()): request.session['practice_greeting'] = practice.greeting_lunch else: request.session['practice_greeting'] = practice.greeting_closed if(practice.skip_to_rmsg and practice.is_open()): request.session['ivr2_state'] = 'PracticeIVR_LeaveRegularMsg_New' r.append(twilio.Play(request.session['practice_greeting'])) r.append(twilio.Redirect(reverse('PracticeIVR_LeaveRegularMsg_New'))) logger.debug('%s: PracticeIVR_CallerResponse_New skip to leave msg for %s open greeting' % ( request.session.session_key, practice)) else: if practice.uses_original_answering_serice(): gather.append(twilio.Play(request.session['practice_greeting'])) r.append(gather) logger.debug('%s: PracticeIVR_CallerResponse_New practice %s orig greeting' % ( request.session.session_key, practice)) else: #layer 1 greeting, it recites call group lists, #populates request.session['call_groups_map'] and request.session['specialty_map'] dynamic_greeting = create_dynamic_greeting(request, practice) request.session['last_played'] = dynamic_greeting gather.append(twilio.Play(request.session['practice_greeting'])) gather.append(tts(_('%s.') % (''.join(request.session['last_played'])))) r.append(gather) logger.debug('%s: PracticeIVR_CallerResponse_New practice %s greeting %s' % ( request.session.session_key, practice, request.session['last_played'])) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def ProviderIVR_ForwardCall_VetAnswer(request): """ This function is executed on Number nouns within Dial verbs. The idea is to try to determine if it's a human who picked up, or a machine. Alternatively, this gives the called party a chance to send the call to voicemail without the caller knowing they're rejecting the call. """ r = twilio.Response() request.session.modified = True callSID = request.POST['CallSid'] log = callLog.objects.get(callSID=callSID) if (request.method == 'POST' and 'Digits' in request.POST): # Connect the calls log.call_connected = True log.save() event = callEvent(callSID=callSID, event='C_ACC') event.save() return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) caller_spoken_name = log.caller_spoken_name if (log.mdcom_caller): # Great. Is it a Provider? if (isinstance(log.mdcom_caller, Provider) and log.mdcom_caller.vm_config.count()): vm_config = log.mdcom_caller.vm_config.get() if (vm_config.config_complete): caller_spoken_name = vm_config.name gather = twilio.Gather(numDigits=1, finishOnKey='', action=reverse('ProviderIVR_ForwardCall_VetAnswer')) gather.append(tts("You have a call from")) gather.append(twilio.Play(caller_spoken_name)) gather.append(tts("Press any key to accept.")) r.append(gather) r.append(twilio.Hangup()) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def ProviderIVR_Options_New(request, twilioResponse=None): """ Options Menu to change VM settings Sets up what we say to user for options choices """ r = twilioResponse or twilio.Response() request.session['ivr2_state'] = 'ProviderIVR_Options_New' # reset sub_state if ('ivr2_sub_state' in request.session): del request.session['ivr2_sub_state'] gather = twilio.Gather(finishOnKey='', numDigits=1, action=reverse('ProviderIVR_Options_Actions')) gather.append(tts('Options menu')) gather.append(tts('To re-record your name, press 1')) gather.append(tts('To record a new greeting, press 3')) gather.append(tts('To change your pin, press 5')) gather.append(tts('To return to the main menu, press 9')) gather.append(tts('To repeat this menu, press star')) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def Twilio_callGather(request): import cPickle # Save debugging data sid = request.POST['CallSid'] status = request.POST['CallStatus'] log = TwilioCallGatherTest.objects.get(callid=sid) if (not log.debug_data): debugData = [] else: debugData = cPickle.loads(log.debug_data.encode('ascii')) newEntry = ['Twilio_callGather', cPickle.dumps(request.POST)] debugData.append(newEntry) log.debug_data = cPickle.dumps(debugData) log.save() # We don't care about which session this is associated with as all # verification is the same across all sessions. r = twilio.Response() if (status != 'completed'): abs_uri = '://'.join([settings.SERVER_PROTOCOL, settings.SERVER_ADDRESS]) url = reverse('MHLogin.tests.views.Twilio_callGather_complete') gather = twilio.Gather(action=urljoin(abs_uri, url), numDigits=1, finishOnKey='', timeout=10) gather.append(twilio.Say("Please press the number one.", voice=twilio.Say.MAN, language=twilio.Say.ENGLISH)) r.append(gather) log.success = log.success + '1' # should be 11 or 101 here debugData.append(str(r)) log.debug_data = cPickle.dumps(debugData) log.save() return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def testAddAttribute(self): """ add attribute """ r = twiml.Gather(foo="bar") r = self.strip(r) assert_equal(r, '<?xml version="1.0" encoding="UTF-8"?><Gather foo="bar" />')
def changePin(request, twilioResponse=None, internalCall=False): """This function gets called three times per successful PIN change. The first time, it requests the user's pin. The second time, it requests confirmation of the pin. The last time, it finally saves the pin, then :returns: to the function specified at request.session['ivr_call_stack'][-1] """ r = twilioResponse or twilio.Response() if (not internalCall and 'Digits' in request.POST): digits = request.POST['Digits'] if (not 'ivr_changePin_hash' in request.session): # This is the first time the PIN has been entered. p = re.compile('\d{4,8}#?$') if (not p.match(digits)): r.append(tts(_("An in valid pin was entered."))) else: request.session['ivr_changePin_hash'] = get_new_pin_hash(digits) gather = twilio.Gather(numDigits=8, action=reverse('changePin')) gather.append(tts(_('To verify that we have the correct pin, ' 'please enter it again. Press pound to finish.'))) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) else: # The PIN has been entered once. Time to verify it. p = re.compile('\d{4,8}#?$') if (p.match(digits)): if (check_pin(digits, request.session['ivr_changePin_hash'])): r.append(twilio.Redirect(reverse(request.session['ivr_call_stack'].pop()))) response = HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) if ('answering_service' in request.session and request.session['answering_service'] == 'yes'): practice = PracticeLocation.objects.get(id=request.session['practice_id']) practice.pin = request.session['ivr_changePin_hash'] practice.save() else: config = VMBox_Config.objects.get(id=request.session['config_id']) # Note: request.user is anon for twilio sessions, issue 1362 # get_user_key assumes cookie has 'ss' and ss def arg None by def old_key = get_user_key(request) if 'ss' in request.COOKIES else None config.change_pin(request, old_key=old_key, new_pin=digits) config.pin = request.session['ivr_changePin_hash'] config.save() del request.session['ivr_changePin_hash'] event = callEvent(callSID=request.POST['CallSid'], event='F_PCH') event.save() request.session.modified = True return response r.append(tts(_('The entered pins do not match.'))) del request.session['ivr_changePin_hash'] if (not 'ivr_changePin_hash' in request.session): # This is the code that gets executed on the first run of this function. # It also gets run if the PIN verification fails. gather = twilio.Gather(numDigits=8, action=reverse('changePin')) gather.append(tts(_("Please enter four to eight digits. Press pound to finish."))) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def playMessages(request, msgs_querySet=None, twilioResponse=None): """Plays and gives the menu tree to act on messages. :param request: the usual Django view argument :param msgs_querySet: django query set of voice messages :param twilioResponse: None if direct from Twilio, set if called within IVR :returns: django.http.HttpResponse -- the result """ # msgs_querySet is None when called from Twilio and session is setup if msgs_querySet != None: # msgs_querySet is not None when called within IVR tree but may be empty set request.session['ivr_playMessages_newMessages'] = list(msgs_querySet.filter( read_flag=False, delete_flag=False).order_by('msg_body__message__message_type', '-msg_body__message__send_timestamp').all()) if len(request.session['ivr_playMessages_newMessages']): request.session['ivr_playMessages_newMsgsFlag'] = True request.session['ivr_playMessages_oldMessages'] = list(msgs_querySet.filter( read_flag=True, delete_flag=False).order_by('msg_body__message__message_type', '-msg_body__message__send_timestamp').all()) # We're pretty much always going to be manipulating the session. request.session.modified = True r = twilioResponse or twilio.Response() replayFlag = False playFlag = True call_sid = request.POST['CallSid'] if (not msgs_querySet and 'Digits' in request.POST): digits = request.POST['Digits'] p = re.compile('[0-9#*]$') if (not p.match(digits)): r.append(tts('I\'m sorry, I didn\'t understand that.')) playFlag = False if (digits == '1'): # do nothing pass elif (digits == '3'): replayFlag = True elif (digits == '5'): return callBackUser(request, request.session['ivr_playMessages_currentMsg'].msg_body.message) elif (digits == '7'): # Merely sets the 'deleted' flag to hide the message. r.append(tts('Message resolved')) event = callEvent(callSID=call_sid, event='V_MDL') event.save() target = callEventTarget(event=event, target=request.session['ivr_playMessages_currentMsg']) target.save() request.session['ivr_playMessages_currentMsg'].\ msg_body.message.resolved_by = request.user elif (digits == '9'): r.append(twilio.Redirect(reverse(request.session['ivr_call_stack'].pop()))) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) if (replayFlag): r.append(tts('Re-playing message')) elif (not playFlag): pass # do nothing -- we don't want to move to the next message. elif (len(request.session['ivr_playMessages_newMessages'])): if (msgs_querySet): r.append(tts('Playing the first new message')) else: r.append(tts('Playing the next new message')) request.session['ivr_playMessages_currentMsg'] = \ request.session['ivr_playMessages_newMessages'].pop(0) event = None if(request.session['ivr_playMessages_currentMsg'].msg_body.message.message_type == 'ANS'): event = callEvent(callSID=call_sid, event='V_NAP') event.save() else: event = callEvent(callSID=call_sid, event='V_NMP') event.save() target = callEventTarget(event=event, target=request.session['ivr_playMessages_currentMsg']) target.save() request.session['ivr_playMessages_currentMsg'].read_flag = True request.session['ivr_playMessages_currentMsg'].save() elif (len(request.session['ivr_playMessages_oldMessages'])): #if (request.session['ivr_playMessages_newMsgsFlag']): # Done playing new messages. # pass if (msgs_querySet): r.append(tts('Playing the first old message')) else: r.append(tts('Playing the next old message')) request.session['ivr_playMessages_currentMsg'] = \ request.session['ivr_playMessages_oldMessages'].pop(0) event = None if(request.session['ivr_playMessages_currentMsg'].msg_body.message.message_type == 'ANS'): event = callEvent(callSID=call_sid, event='V_OAP') event.save() else: event = callEvent(callSID=call_sid, event='V_OMP') event.save() target = callEventTarget(event=event, target=request.session['ivr_playMessages_currentMsg']) target.save() else: r.append(tts('End of messages')) r.append(twilio.Redirect(reverse(request.session['ivr_call_stack'].pop()))) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) gather = twilio.Gather(finishOnKey='', numDigits=1, action=reverse('playMessages')) if (playFlag): url = '' if (request.session['ivr_playMessages_currentMsg'].\ msg_body.message.message_type == 'ANS'): spoken_number = [] digits = request.session['ivr_playMessages_currentMsg'].\ msg_body.message.callback_number [spoken_number.extend([i, ' ']) for i in digits] spoken_number.pop() # drop the last element #spoken_number.insert(5, ',') #spoken_number.insert(12, ',') gather.append(tts('Call from %s .' % (''.join(spoken_number),))) msg = request.session['ivr_playMessages_currentMsg'].msg_body.message try: uuid = MessageAttachment.objects.get(message=msg).uuid url = reverse("fetchRecording", kwargs={"uuid": uuid}) gather.append(twilio.Play(url)) except MessageAttachment.DoesNotExist: errors = { 'U': _("User hung up before confirming number."), 'C': _("User hung up before leaving message."), 'R': _("An error occurred downloading the recording. We will retry until " "successful and you will receive a new message at that time."), } gather.append(tts(errors[msg.vmstatus])) gather.append(twilio.Pause()) gather.append(tts(_('Press 1 to move to the next message. '))) gather.append(tts(_('Press 3 to re-play the message. '))) callback_number = request.session['ivr_playMessages_currentMsg'].\ msg_body.message.callback_number if(re.match("1?\d{10}", callback_number)): gather.append(tts(_('Press 5 to call this person back. '))) gather.append(tts(_('Press 7 to mark the message resolved and hide it. '))) gather.append(tts(_('Press 9 to return to the main menu. '))) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def ProviderIVR_ForwardCall_Vet(request): """ This function is executed on Number nouns within Dial verbs. The idea is to try to determine if it's a human who picked up, or a machine. Alternatively, this gives the called party a chance to send the call to voicemail without the caller knowing they're rejecting the call. """ logger.debug('%s: ProviderIVR_ForwardCall_Vet POST %s' % (request.session.session_key, str(request.POST))) r = twilio.Response() callSID = request.POST['CallSid'] # second leg calls have their own callSIDs - may need parentCallSID (log, plog) = _getCallLogOrParent(request) if (request.method == 'POST' and 'Digits' in request.POST): # Connect the calls, get parent log if any if log: logger.debug( '%s: ProviderIVR_ForwardCall_Vet connected callsid %s logSID %s' % (request.session.session_key, callSID, log.callSID)) log.call_connected = True log.save() if plog: plog.call_connected = True plog.save() logger.debug( '%s: ProviderIVR_ForwardCall_Vet update parent of logsid %s plogSID %s' % (request.session.session_key, log.callSID, plog.callSID)) else: logger.debug( '%s: ProviderIVR_ForwardCall_Vet connected log not found %s' % (request.session.session_key, callSID)) event = callEvent(callSID=request.POST['CallSid'], event='C_ACC') event.save() return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) if log: caller_spoken_name = log.caller_spoken_name if (log.mdcom_caller): # Great. Is it a Provider? if (isinstance(log.mdcom_caller, Provider) and log.mdcom_caller.vm_config.count()): vm_config = log.mdcom_caller.vm_config.get() if (vm_config.config_complete): caller_spoken_name = vm_config.name else: logger.debug( '%s: ProviderIVR_ForwardCall_Vet call log sid %s not found' % (request.session.session_key, callSID)) gather = twilio.Gather(numDigits=1, finishOnKey='', action=reverse('ProviderIVR_ForwardCall_Vet')) gather.append(tts("You have a call from")) gather.append(twilio.Play(caller_spoken_name)) gather.append(tts("Press any key to accept.")) r.append(gather) r.append(twilio.Hangup()) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def ProviderIVR_TreeRoot_New(request, provider=None, twilioResponse=None): """ call tree of a provider: 1 to listen to all msgs; 2 to listen to urgent msgs 3 to listen to voice mail 4 to manage voicemail settings * to repeat menu Require: session variable: provider_id to be set Require: request.session['ivr2_state'] == ProviderIVR_TreeRoot_New sets up twilio response with message and url to go to ProviderIVR_TreeRoot_Actions """ if (provider == None): provider = Provider.objects.get(id=request.session['provider_id']) logger.debug('%s: ProviderIVR_TreeRoot_New prov %s' % (request.session.session_key, provider)) request.session['ivr2_state'] = 'ProviderIVR_TreeRoot_New' unread_anssvc_msg_count = MessageBodyUserStatus.objects.filter( user=provider.user, read_flag=False, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type='ANS').count() unread_msg_count = MessageBodyUserStatus.objects.filter( user=provider.user, read_flag=False, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type='VM').count() saved_msg_count = MessageBodyUserStatus.objects.filter( user=provider.user, read_flag=True, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type='VM').count() saved_anssvc_msg_count = MessageBodyUserStatus.objects.filter( user=provider.user, read_flag=True, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type='ANS').count() logger.debug('%s: ProviderIVR_TreeRoot_New msg counts %d, %d, %d, %d' % (request.session.session_key, unread_anssvc_msg_count, unread_msg_count, saved_msg_count, saved_anssvc_msg_count)) say_str = [] say_str.append('You have %i new, and %i saved urgent messages,' % (unread_anssvc_msg_count, saved_anssvc_msg_count)) say_str.append(' ') say_str.append('and %i new, and %i saved voice messages,' % (unread_msg_count, saved_msg_count)) if (any((unread_msg_count, unread_anssvc_msg_count, saved_msg_count, saved_anssvc_msg_count))): say_str.append('To listen to all your messages, press one. ') say_str.append('To listen to your urgent messages, press two. ') say_str.append('To listen to your voice mail, press three. ') r = twilioResponse or twilio.Response() gather = twilio.Gather(action=reverse('ProviderIVR_TreeRoot_Actions'), finishOnKey='', numDigits=1) gather.append(tts(''.join(say_str))) gather.append(tts('To manage your voicemail settings, press four.')) gather.append(tts('To repeat this menu, press star.')) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def authenticateSession(request, twilioResponse=None): """ :param request: The standard Django request argument :param request.session Keys: config_id - The ID of the VMBox_Config object pertaining to the current voicemail session. :param twilioResponse: A twilio response object. Use this to pass in any verbs that should be run before the prompt. Note that any verbs passed in will be lost on subsequent runs through this function (e.g., when the user enters an incorrect pin) :returns: django.http.HttpResponse -- the result """ r = twilioResponse or twilio.Response() if (not 'pin_errCount' in request.session): request.session['pin_errCount'] = 0 if 'Digits' in request.POST: call_sid = request.POST['CallSid'] digits = request.POST['Digits'] p = re.compile('\d{4,8}#?$') if (p.match(digits)): if ('answering_service' in request.session and request.session['answering_service'] == 'yes'): practice = PracticeLocation.objects.get(id=request.session['practice_id']) if (practice.verify_pin(digits)): request.session['authenticated'] = True r.append(twilio.Redirect(reverse(request.session['ivr_call_stack'].pop()))) request.session.modified = True return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) else: user = authenticate(config_id=request.session['config_id'], pin=digits) if (user): login(request, user) # TESTING_KMS_INTEGRATION uprivs = UserPrivateKey.objects.filter(user=user, credtype=CRED_IVRPIN, gfather=True) if uprivs.exists(): config = VMBox_Config.objects.get(id=request.session['config_id']) config.change_pin(request, new_pin=digits) request.session['authenticated'] = True event = callEvent(callSID=call_sid, event='V_ASU') event.save() r.append(twilio.Redirect(reverse(request.session['ivr_call_stack'].pop()))) request.session.modified = True response = HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) store_user_key(request, response, digits) return response event = callEvent(callSID=call_sid, event='V_AFL') event.save() r.append(tts('An in valid pin was entered.')) request.session['pin_errCount'] += 1 if (request.session['pin_errCount'] >= 3): # give the user three erroneous pin entries. r.append(tts('Good bye.')) r.append(twilio.Hangup()) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) # This is the code that gets executed on the first run of this function. gather = twilio.Gather(numDigits=8, action=reverse('authenticateSession')) gather.append(tts(_("Please enter your pin number. Press pound to finish."))) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def testNoDeclaration(self): """ add attribute """ r = twiml.Gather(foo="bar") assert_equal(r.toxml(xml_declaration=False), '<Gather foo="bar" />')
def PracticeIVR_CallerResponse_Action(request, twilioResponse=None): """ This function process callers response in 2 ways: old way (original answering service): 1=leave msg in doc com mailbox via PracticeIVR_LeaveRegularMsg_New (to all practice managers) 2=page doctor on call (LeaveUrgentMsg_New) new way (dynamic greeting already called): create greeting based on call_groups info in db if 1 call group for THIS practice, take message via PracticeIVR_LeaveRegularMsg_New if > 1 call group, add a layer to first pick call group, then pick type of message PracticeIVR_ForwardCall_New """ practice = PracticeLocation.objects.get(id=request.session['practice_id']) logger.debug('%s: PracticeIVR_CallerResponse_Action practice %s POST data is %s' % ( request.session.session_key, practice, str(request.POST))) r = twilioResponse or twilio.Response() if (request.method == 'POST' and 'Digits' in request.POST): digits = request.POST['Digits'] if practice.uses_original_answering_serice(): # old way logger.debug('%s: PracticeIVR_CallerResponse_Action via old ans svc' % ( request.session.session_key)) p = re.compile('[0-9#*]$') if (not p.match(digits)): r.append(tts(_('I\'m sorry, I didn\'t understand that.'))) elif (digits == '1'): # leave msg in doctor com mailbox request.session['ivr2_state'] = 'PracticeIVR_LeaveRegularMsg_New' request.session.modified = True return PracticeIVR_LeaveRegularMsg_New(request) elif (digits == '2'): # forward the call request.session['ivr2_state'] = 'PracticeIVR_ForwardCall_New' request.session.modified = True request.session['provider_id'] = _getRecentOncallProviderId(request) logger.debug('%s: PracticeIVR_CallerResponse_Action old ans svc NO oncall provider' % (request.session.session_key)) if(not request.session['provider_id']): r.append(tts(_('We\'re sorry, an application error has occurred. Goodbye.', voice='woman'))) r.append(twilio.Hangup()) # return r return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) return PracticeIVR_ForwardCall_New(request) elif (digits == '*'): pass else: r.append(tts(_('I\'m sorry, I didn\'t understand that.'))) return PracticeIVR_CallerResponse_New(request, r) else: # new V2 dynamic greeting and call groups call_groups_map = request.session['call_groups_map'] specialties_map = request.session['specialties_map'] logger.debug('%s: PracticeIVR_CallerResponse_Action via new ans svc cg %s sp %s' % ( request.session.session_key, call_groups_map, specialties_map)) gather = twilio.Gather(action=reverse('PracticeIVR_CallerResponse_Action'), finishOnKey='', numDigits=1, timeout=60) p = re.compile('[0-9]$') if (not p.match(digits)): r.append(tts(_('I\'m sorry, I didn\'t understand that.'))) r.append(tts(_('%s.') % (''.join(request.session['last_played']),))) r.append(gather) elif (digits == '1' and request.session['one_ok'] == '1'): # one_ok is set in create_dynamic_greeting # leave msg in doctor com mailbox request.session['ivr2_state'] = 'PracticeIVR_LeaveRegularMsg_New' request.session.modified = True return PracticeIVR_LeaveRegularMsg_New(request) elif (digits in call_groups_map): #Call Group reached, get provider on call request.session['callgroup_id'] = call_groups_map.get(digits) request.session['ivr2_state'] = 'PracticeIVR_ForwardCall_New' request.session.modified = True request.session['provider_id'] = _getRecentOncallProviderId(request) logger.debug('%s: PracticeIVR_CallerResponse_Action new ans svc NO oncall provider' % (request.session.session_key)) if(not request.session['provider_id']): r.append(tts(_('We\'re sorry, an application error has occurred. Goodbye.', voice='woman'))) r.append(twilio.Hangup()) # return r return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) return PracticeIVR_ForwardCall_New(request) elif (digits in specialties_map): #specialty reached, get list of call groups, #populates request.session['call_groups_map'] and blanks out request.session['specialty_map'] call_groups_greeting = create_call_group_list(request, specialties_map.get(digits)) gather.append(tts(_('%s.') % (''.join(call_groups_greeting),))) request.session['last_played'] = call_groups_greeting r.append(gather) #elif (digits == '*'): treat * as invalid input #pass else: gather.append(tts(_('I\'m sorry, I didn\'t understand that.'))) gather.append(tts(_('%s.') % (''.join(request.session['last_played']),))) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) else: # should never happen - but if we get here without Digits, we log and go back to Main logger.debug('%s: PracticeIVR_CallerResponse_Action is called with no post or digits' % (request.session.session_key)) request.session['ivr2_state'] = 'PracticeIVR_Main_New' return PracticeIVR_Main_New(request)
def ProviderIVR_TreeRoot(request): r = twilio.Response() provider = Provider.objects.get(id=request.session['provider_id']) if (request.method == 'POST' and 'Digits' in request.POST): digits = request.POST['Digits'] p = re.compile('[0-9#*]$') if (not p.match(digits)): r.append(tts('I\'m sorry, I didn\'t understand that.')) elif (digits == '1'): # play messages request.session['ivr_call_stack'].append('ProviderIVR_TreeRoot') request.session.modified = True messages = MessageBodyUserStatus.objects.filter( user=provider.user, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type__in=('ANS', 'VM')) return playMessages(request, messages, r) elif (digits == '2'): request.session['ivr_call_stack'].append('ProviderIVR_TreeRoot') request.session.modified = True messages = MessageBodyUserStatus.objects.filter( user=provider.user, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type__in=('ANS', )) return playMessages(request, messages, r) elif (digits == '3'): request.session['ivr_call_stack'].append('ProviderIVR_TreeRoot') request.session.modified = True messages = MessageBodyUserStatus.objects.filter( user=provider.user, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type__in=('VM', )) # fix for issue 2257 - if we go to playMessages, it will use 3 in its digit and try to replay # current message which fails if there are no messages if (messages == [] or len(messages) == 0): pass else: request.session['ivr_call_stack'].append( 'ProviderIVR_TreeRoot') return playMessages(request, messages, r) elif (digits == '4'): request.session['ivr_call_stack'].append('ProviderIVR_TreeRoot') request.session.modified = True return ProviderIVR_Options(request, True) elif (digits == '*'): pass else: r.append(tts('I\'m sorry, I didn\'t understand that.')) gather = twilio.Gather(finishOnKey='', numDigits=1) # messages = MessageBodyUserStatus unread_anssvc_msg_count = MessageBodyUserStatus.objects.filter( user=provider.user, read_flag=False, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type='ANS').count() unread_msg_count = MessageBodyUserStatus.objects.filter( user=provider.user, read_flag=False, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type='VM').count() saved_msg_count = MessageBodyUserStatus.objects.filter( user=provider.user, read_flag=True, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type='VM').count() saved_anssvc_msg_count = MessageBodyUserStatus.objects.filter( user=provider.user, read_flag=True, delete_flag=False, msg_body__message___resolved_by=None, msg_body__message__message_type='ANS').count() say_str = [] say_str.append('You have %i new, and %i saved urgent messages,' % (unread_anssvc_msg_count, saved_anssvc_msg_count)) say_str.append(' ') say_str.append('and %i new, and %i saved voice messages,' % (unread_msg_count, saved_msg_count)) if (any((unread_msg_count, unread_anssvc_msg_count, saved_msg_count, saved_anssvc_msg_count))): say_str.append('To listen to all your messages, press one. ') say_str.append('To listen to your urgent messages, press two. ') say_str.append('To listen to your voice mail, press three. ') gather.append(tts(''.join(say_str))) gather.append(tts('To manage your voicemail settings, press four.')) gather.append(tts('To repeat this menu, press star.')) r.append(gather) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE)
def getCallBackNumber(request, twilioResponse=None): """ Gets call back number from users input, verifies number, sends it back to be used in msg or sms """ if 'CallStatus' in request.POST: logger.debug('%s: Into getCallBackNumber with call status %s' % ( request.session.session_key, request.POST['CallStatus'])) r = twilioResponse or twilio.Response() request.session.modified = True if ('CallStatus' in request.POST and request.POST['CallStatus'] == 'completed'): # First, check to see if the caller has hung up. if ('ivr_has_number' in request.session and 'ivr_callback_returnOnHangup' in request.session and 'ivr_makeRecording_callbacknumber' in request.session): #call caller function, just to send empty msg or sms request.session['ivr_only_callbacknumber'] = True view = request.session.get('ivr_callback_returnOnHangup', None) if view: try: # TODO: no more exec() but validation on view is needed mod, func = view.rsplit('.', 1) mod = import_module(mod) getattr(mod, func)(request) # call the view function except Exception as e: mail_admins("Problem calling view in getCallBackNumber", str(e)) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) # after hung up we need to clear first time < 10 digit numbers for urgent calls if ('ivr_urgent_second_time' in request.session): request.session.pop('ivr_makeRecording_callbacknumber', None) request.session.pop('ivr_caller_id_area_code', None) if 'Digits' in request.POST: digits = request.POST['Digits'] if ('ivr_makeRecording_callbacknumber' in request.session): p = re.compile('[0-9]$') if (not p.match(digits)): del request.session['ivr_makeRecording_callbacknumber'] del request.session['ivr_has_number'] request.session.pop('ivr_caller_id_area_code', None) r.append(tts('I\'m sorry, I didn\'t understand that.')) r.append(twilio.Redirect(reverse('getCallBackNumber'))) elif (digits == '1'): # correct number - leave function, and get voice recordng r.append(twilio.Redirect(reverse(request.session['ivr_call_stack'].pop()))) request.session.modified = True #r.append(twilio.Redirect(reverse('getCallBackNumber'))) elif (digits == '3'): #user said, bad number, reinit and enter number again del request.session['ivr_makeRecording_callbacknumber'] del request.session['ivr_has_number'] request.session.pop('ivr_caller_id_area_code', None) r.append(twilio.Redirect(reverse('getCallBackNumber'))) else: r.append(tts('I\'m sorry, I didn\'t understand that.')) gather = twilio.Gather(finishOnKey='', numDigits=1, action=reverse('getCallBackNumber')) spoken_number = [] [spoken_number.extend([i, ' ']) for i in request.session['ivr_makeRecording_callbacknumber']] spoken_number.pop() # drop the last element gather.append(tts(_('Eye got %s. If this is correct, press one. Or' 'press three to enter eh different number') % (''.join(spoken_number),))) r.append(gather) #r.append(twilio.Redirect(reverse('getCallBackNumber'))) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) if ('ivr_has_number' in request.session): #first time thru phone was entered ivr_makeRecording_callbacknumber does # not have phone number in it yet. if (not 'ivr_makeRecording_callbacknumber' in request.session or 'ivr_urgent_second_time' in request.session): if(re.match(r'[0-9]+', digits)): spoken_number = [] [spoken_number.extend([i, ' ']) for i in digits] spoken_number.pop() # drop the last element #spoken_number.insert(5, ',') #spoken_number.insert(12, ',') request.session['ivr_makeRecording_callbacknumber'] = digits #take first three digits from caller, in case less than 10 digits are # entered, we do this for ALL calls where call back number is < 10 digits if (len(digits) < 10 and 'Caller' in request.session and len(request.session['Caller']) > 2): request.session['ivr_caller_id_area_code'] = request.session['Caller'][0:3] # for bug 829, ONLY on FIRST pass, we need to make sure its at least # 10 digits, if not say please make sure you entered area code # only if this is URGENT call, rest of callers are free to leave any # number of digits also, if after first try, users still enters < 10 # digits, let it go thru (ivr_urgent_second_time var is used for that) view = request.session.get('ivr_callback_returnOnHangup', None) if (not 'ivr_urgent_second_time' in request.session and len(digits) < 10 and view and view.split('.')[-1] == 'PracticeIVR_LeaveUrgentMsg'): gather = twilio.Gather(finishOnKey='#', numDigits=12, timeout=30, action=reverse('getCallBackNumber')) gather.append(tts('I\'m sorry, It appears your call back number ' 'is less than ten digits. Please enter your call back ' 'number including area code now. Then press pound.')) r.append(gather) r.append(twilio.Redirect(reverse('getCallBackNumber'))) request.session['ivr_urgent_second_time'] = True return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) #========= end of bug 829 ======================= else: gather = twilio.Gather(finishOnKey='', numDigits=1, action=reverse('getCallBackNumber')) gather.append(tts('Eye got %s . If this is correct, press one. ' 'Or press three to enter eh different number' % \ (''.join(spoken_number),))) r.append(gather) r.append(twilio.Redirect(reverse('getCallBackNumber'))) request.session.pop('ivr_urgent_second_time', None) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) else: r.append(tts(_('I\'m sorry, I didn\'t understand that.'))) r.append(twilio.Redirect(reverse('getCallBackNumber'))) request.session.pop('ivr_has_number', None) request.session.pop('ivr_makeRecording_callbacknumber', None) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) if (not 'ivr_has_number' in request.session): # This is the code that gets executed on the first run of this function. #'digits' get posted for next itteration # It also gets run if the call back number verification fails gather = twilio.Gather(finishOnKey='#', numDigits=12, timeout=30, action=reverse('getCallBackNumber')) gather.append(tts(_('On the keypad, please enter your call back number ' 'including area code now, then press pound.'))) r.append(gather) r.append(twilio.Redirect(reverse('getCallBackNumber'))) request.session['ivr_has_number'] = True return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) #this is the case of user pressing just pound at call back number, there are no digits. if ('ivr_has_number' in request.session and 'Digits' not in request.POST): del request.session['ivr_has_number'] request.session.pop('ivr_makeRecording_callbacknumber', None) r.append(tts(_('I\'m sorry, I didn\'t understand that.'))) r.append(twilio.Redirect(reverse('getCallBackNumber'))) return HttpResponse(str(r), mimetype=settings.TWILIO_RESPONSE_MIMETYPE) raise Exception(_('should never get here'))