class CollectDigitsRunner(Runner): """User's single interaction to enter a set of digits Note: Asterisk is hard-coded to use # to exit the entry-mode... """ def __call__(self, *args, **named): """Begin the AGI processing for the menu""" self.readDigits() return self.finalDF def readDigits(self, result=None): """Begin process of reading digits from the user""" soundFile = getattr(self.model, 'soundFile', None) if soundFile: # easiest possibility, just read out the file... return self.agi.getData( soundFile, timeout=self.model.timeout, maxDigits = getattr(self.model, 'maxDigits', None), ).addCallback(self.onReadDigits).addErrback(self.returnError) else: raise NotImplemented("""Haven't got non-soundfile menus working yet""") self.agi.getData(self.menu. filename, timeout=2.000, maxDigits=None) def validEntry(self, digits): """Determine whether given digits are considered a "valid" entry""" minDigits = getattr(self.model, 'minDigits', None) if minDigits is not None: if len(digits) < minDigits: return False, 'Too few digits' return True, None def onReadDigits(self, (digits,timeout)): """Deal with succesful result from reading digits""" log.info("""onReadDigits: %r, %s""", digits, timeout) valid, reason = self.validEntry(digits) if (not digits) and (not timeout): # user pressed # raise error.MenuExit( self.model, """User cancelled entry of digits""", ) if not valid: if self.model.tellInvalid: # this should be a menu, letting the user decide to re-enter, # or cancel entry pass self.alreadyRepeated += 1 if self.alreadyRepeated >= self.model.maxRepetitions: log.warn("""User did not complete digit-entry for %s, timing out""", self.model) raise error.MenuTimeout( self.model, """User did not finish digit-entry in %s passes of collection""" % ( self.alreadyRepeated, ) ) return self.readDigits() else: # Yay, we got a valid response! return self.returnResult([(self, digits)])
def onReadDigits(self, values): """Deal with succesful result from reading digits""" (digits, timeout) = values log.info("""onReadDigits: %r, %s""", digits, timeout) valid, reason = self.validEntry(digits) if (not digits) and (not timeout): # user pressed # raise error.MenuExit( self.model, """User cancelled entry of digits""", ) if not valid: if self.model.tellInvalid: # this should be a menu, letting the user decide to re-enter, # or cancel entry pass self.alreadyRepeated += 1 if self.alreadyRepeated >= self.model.maxRepetitions: log.warn( """User did not complete digit-entry for %s, timing out""", self.model) raise error.MenuTimeout( self.model, """User did not finish digit-entry in %s passes of collection""" % (self.alreadyRepeated, )) return self.readDigits() else: # Yay, we got a valid response! return self.returnResult([(self, digits)])
def __call__(self, pressed, parent): """Raise a MenuExit error""" raise error.MenuExit( self, pressed, parent, """User selected ExitOn option""", )
def onReadPrompt(self, result): """We've finished reading the prompt to the user, check for escape""" log.info('Finished reading prompt for collect audio: %r', result) if result and result in self.escapeDigits: raise error.MenuExit( self.model, """User cancelled entry of audio during prompt""", ) else: return self.collectAudio()
def validEntry(self, digits): """Determine whether given digits are considered a "valid" entry""" for digit in self.model.escapeDigits: if digit in digits: raise error.MenuExit( self.model, """User cancelled entry of password""", ) if digits != self.expected: return False, "Password doesn't match" return True, None
def onAudioCollected(self, result): """Process the results of collecting the audio""" digits, typeOfExit, endpos = result if typeOfExit in ('hangup', 'timeout'): # expected common-case for recording... return self.returnResult((self,(digits,typeOfExit,endpos))) elif typeOfExit =='dtmf': raise error.MenuExit( self.model, """User cancelled entry of audio""", ) else: raise ValueError("""Unrecognised recordFile results: (%s, %s %s)""" % ( digits, typeOfExit, endpos, ))