Пример #1
0
    def handle(self, text):
        # make sure they are registered with the system
        if not (self.msg.contact and self.msg.contact.is_help_admin):
            self.respond(self.UNGREGISTERED)
            return

        text = text.strip()
        if not text:
            self.help()
            return

        location_slug = text.split()[0][0:6] #get only PPDDFF from 1st token
        try:
            txt_count = text.split()[1]
            ic = InputCleaner()
            count = ic.words_to_digits(txt_count)
        except (IndexError, ValueError, AttributeError):
            count = 5
            
        if count == 0:
            count = 5

        try:
            location = Location.objects.get(slug__iexact=location_slug)
        except Location.DoesNotExist:
            self.respond("Sorry, I don't know about a location with code "
                         "%(code)s. Please check your code and try again.",
                         code=location_slug)
            return

        active_contacts = Contact.active.filter(Q(location=location) |
                                                Q(location__parent=location),
                                                Q(types=
                                                const.get_clinic_worker_type()))\
                                                .order_by('pk')
        if active_contacts:
            contact_list = " ****".join(contact.name + ";"
                                        + contact.default_connection.identity + "."
                                        for contact in active_contacts[0:count])
            self.respond("Contacts at %s: %s" %
                         (location.name, contact_list))
        else:
            self.respond("There are no active contacts at %s" % location.name)
Пример #2
0
    def handle(self, text):
        original_text = text
        if not self.msg.contact:
            self.respond(UNGREGISTERED)
            return
        b = InputCleaner()
        try:
            count = int(b.try_replace_oil_with_011(text.strip()))
        except ValueError:
            text = b.words_to_digits(text)
            if not text:
                text= self.get_only_number(original_text)
                if text:
                    count = int(text)
                else:
                    self.respond("%s %s" % (SORRY, HELP))
                    return
            else:
                self.info("Converted %s to %s" % (original_text, text))
                count = int(text)
                count = abs(count) #just in case we change our general cleaning routine           
        
        if count < 1:
            self.respond("Sorry, the number of DBS samples sent must be greater than 0 (zero).")
            return

        # record this in our records    
        SampleNotification.objects.create(contact=self.msg.contact, 
                                          location=self.msg.contact.location,
                                          count=count,
                                          count_in_text=original_text[0:160])
        clinic = get_clinic_or_default(self.msg.contact)
        self.respond(SENT, name=self.msg.contact.name, count=count,
                     clinic=clinic)
                     
        
Пример #3
0
    def handle(self, text):
        original_text = text
        if not self.msg.contact:
            self.respond(UNGREGISTERED)
            return
        b = InputCleaner()
        try:
            count = int(b.try_replace_oil_with_011(text.strip()))
        except ValueError:
            text = b.words_to_digits(text)
            if not text:
                text= self.get_only_number(original_text)
                if text:
                    count = int(text)
                else:
                    self.respond("%s %s" % (SORRY, HELP))
                    return
            else:
                self.info("Converted %s to %s" % (original_text, text))
                count = int(text)
                count = abs(count) #just in case we change our general cleaning routine           
        
        if count < 1:
            self.respond("Sorry, the number of DBS samples sent must be greater than 0 (zero).")
            return

        # record this in our records    
        SampleNotification.objects.create(contact=self.msg.contact, 
                                          location=self.msg.contact.location,
                                          count=count,
                                          count_in_text=original_text[0:160])
        clinic = get_clinic_or_default(self.msg.contact)
        self.respond(SENT, name=self.msg.contact.name, count=count,
                     clinic=clinic)
                     
        
Пример #4
0
    def handle(self, text):
        b = InputCleaner()
        if not is_eligible_for_results(self.msg.connection):
            # essentially checking for an active clinic_worker
            self.respond(self.INELIGIBLE)
            return

        text = text.strip()
        text = b.remove_double_spaces(text)
        location = self.msg.contact.location
        if location.type == const.get_zone_type():
            location = location.parent
        cba = None

        if text[1:].isdigit() and len(text) >= self.MIN_PHONE_LENGTH:
            try:
                cba = \
                Contact.active.get(connection__identity__icontains=text,
                                   location__parent=location,
                                   types=const.get_cba_type())
            except Contact.DoesNotExist:
                self.respond('The phone number %(phone)s does not belong to any'
                             + ' CBA at %(clinic)s. Make sure you typed it '
                             + 'correctly', phone=text, clinic=location)
            except Contact.MultipleObjectsReturned:
                logger.warning("Bug. phone number %s is used by multiple cba's "
                +"at same clinic" % text)
                return

        if not cba:
            cbas = \
            Contact.active.filter(name__icontains=text,
                                  location__parent=location,
                                  types=const.get_cba_type())
            if not cbas:
                self.respond('The name %(name)s does not belong to any'
                             + ' CBA at %(clinic)s. Make sure you typed it '
                             + 'correctly', name=text,
                             clinic=location)
                return
            if len(cbas) == 1:
                cba = cbas[0]
            elif len(cbas) < 5:
                self.respond("Try sending DEREGISTER <CBA_PHONE_NUMBER>. Which "
                             + "CBA did you mean? %(cbas)s", cbas=' or '.join(
                             cba.name + ":" + cba.default_connection.identity
                             for cba in cbas))
                return
            else:
                self.respond("There are %(len)s CBA's who's names match %(name)s"
                             + " at %(clinic)s. Try to use the phone number "
                             + "instead", len=len(cbas), name=text,
                             clinic=location.name)
                return
        if cba:
            cba.is_active = False
            cba.save()
            self.respond("You have successfully deregistered %(name)s:"
                         + "%(phone)s of zone %(zone)s at %(clinic)s",
                         name=cba.name, phone=cba.default_connection.identity,
                         zone=cba.location.name, clinic=location.name)
            worker = self.msg.contact
            for help_admin in Contact.active.filter(is_help_admin=True):
                OutgoingMessage(
                                help_admin.default_connection,
                                "%s:%s has deregistered %s:%s of zone %s at %s" %
                                (worker.name,
                                worker.default_connection.identity,
                                cba.name,
                                cba.default_connection.identity,
                                cba.location.name,
                                location.name
                                )).send()
Пример #5
0
    def handle(self, text):
        # make sure they are registered with the system
        if not (self.msg.contact and self.msg.contact.is_help_admin):
            self.respond(self.UNGREGISTERED)
            return

        text = text.strip()
        if not text:
            self.help()
            return
        start_days_ago = end_days_ago = 0
        ic = InputCleaner()
        try:
            txt_start_days_ago = text.split()[0]
            start_days_ago = int(ic.words_to_digits(txt_start_days_ago))
        except (IndexError, ValueError, AttributeError, TypeError):
            start_days_ago = 0
        try:
            txt_end_days_ago = text.split()[1]
            end_days_ago = int(ic.words_to_digits(txt_end_days_ago))
        except (IndexError, ValueError, AttributeError, TypeError):
            end_days_ago = 0
        if start_days_ago < end_days_ago:
            start_days_ago, end_days_ago = end_days_ago, start_days_ago

        now = datetime.date.today()
        today = datetime.datetime(now.year, now.month, now.day)
        
        startdate = today - datetime.timedelta(days=start_days_ago)
        enddate = today - datetime.timedelta(days=end_days_ago - 1) - \
                    datetime.timedelta(seconds=0.1)

#        Not sure if uncommenting the code below will improve performance.
#        payloads = Payload.objects.filter(Q(incoming_date__gt=startdate) |
#                                          Q(incoming_date=startdate),
#                                          Q(incoming_date__lt=enddate) |
#                                          Q(incoming_date=enddate))

#        if not payloads:
#            self.respond("Period %(startdate)s to %(enddate)s. No payloads",
#                         startdate=startdate.strftime("%d/%m/%Y"),
#                         enddate=enddate.strftime("%d/%m/%Y"))
#            return

        from django.db import connection
        cursor = connection.cursor()

        cursor.execute('select source, count(*) as count from \
             labresults_payload where incoming_date BETWEEN %s AND %s group by \
             source', [startdate, enddate])
        rows = cursor.fetchall()
        if not rows:
            self.respond("Period %(startdate)s to %(enddate)s. No payloads",
                         startdate=startdate.strftime("%d/%m/%Y"),
                         enddate=enddate.strftime("%d/%m/%Y"))
            return

        #build formartted message
        msg_header = 'PAYLOADS. Period: %s to %s. ' % (startdate.strftime("%d/%m/%Y")
                                                       , enddate.strftime("%d/%m/%Y"))
        msg_data = ' ****'.join(row[0] + ";" + str(row[1]) for row in rows)
        full_msg = msg_header + msg_data

        self.respond(full_msg)




        
Пример #6
0
    def handle(self, text):
        b = InputCleaner()
        if is_eligible_for_results(self.msg.connection):
            # refuse re-registration if they're still active and eligible
            self.respond(self.ALREADY_REGISTERED, 
                         name=self.msg.connection.contact.name,
                         location=self.msg.connection.contact.location)
            return
        
        text = text.strip()
        text = b.remove_double_spaces(text)
        if len(text) < (self.PIN_LENGTH + self.MIN_CLINIC_CODE_LENGTH + self.MIN_NAME_LENGTH + 1):
            self.mulformed_msg_help()
            return

        #signed pin
        if text[-5:-4] == '-' or text[-5:-4] == '+':
            self.invalid_pin(text[-5:])
            return
        #too long pin
        if ' ' in text and text[1 + text.rindex(' '):].isdigit() and len(text[1 + text.rindex(' '):]) > self.PIN_LENGTH:
            self.invalid_pin(text[1 + text.rindex(' '):])
            return
        #non-white space before pin
        if text[-5:-4] != ' ' and text[-4:-3] != ' ':
            self.respond("Sorry, you should put a space before your pin. "
                         "Please make sure your code is a %s-digit number like %s. "
                         "Send JOIN <CLINIC CODE> <YOUR NAME> <SECURITY CODE>." % (
                         self.PIN_LENGTH, ''.join(str(i) for i in range(1, int(self.PIN_LENGTH) + 1))))
            return
        #reject invalid pin
        user_pin = text[-4:]
        if not user_pin:
            self.help()
            return
        elif len(user_pin) < 4:
            self.invalid_pin(user_pin)
            return
        elif not user_pin.isdigit():
            self.invalid_pin(user_pin)
            return

        
        group = self.PATTERN.search(text)
        if group is None:
            self.mulformed_msg_help()
            return

        tokens = group.groups()
        if not tokens:
            self.mulformed_msg_help()
            return

        clinic_code = tokens[0].strip()
        clinic_code = b.try_replace_oil_with_011(clinic_code)
        #we expect all codes have format PPDDFF or PPDDFFS
        clinic_code = clinic_code[0:6]
        name = tokens[2]
        name = name.title().strip()
        pin = tokens[4].strip()
        if len(pin) != self.PIN_LENGTH:
            self.respond(self.INVALID_PIN)
            return
        if not name:
            self.respond("Sorry, you must provide a name to register. %s" % self.HELP_TEXT)
            return
        elif len(name) < self.MIN_NAME_LENGTH:
            self.respond("Sorry, you must provide a valid name to register. %s" % self.HELP_TEXT)
            return
        try:
            location = Location.objects.get(slug__iexact=clinic_code,
                                            type__slug__in=const.CLINIC_SLUGS)
            if self.msg.connection.contact is not None \
               and self.msg.connection.contact.is_active:
                # this means they were already registered and active, but not yet 
                # receiving results.
                clinic = get_clinic_or_default(self.msg.connection.contact) 
                if clinic != location:
                    self.respond(self.ALREADY_REGISTERED,
                                 name=self.msg.connection.contact.name,
                                 location=clinic)
                    return True
                else: 
                    contact = self.msg.contact
            else:
                contact = Contact(location=location)
                clinic = get_clinic_or_default(contact)
            contact.name = name
            contact.pin = pin
            contact.save()
            contact.types.add(const.get_clinic_worker_type())
            
            self.msg.connection.contact = contact
            self.msg.connection.save()
            
            self.respond("Hi %(name)s, thanks for registering for "
                         "Results160 from %(location)s. "
                         "Your PIN is %(pin)s. "
                         "Reply with keyword 'HELP' if this is "
                         "incorrect", name=contact.name, location=clinic.name,
                         pin=pin)
        except Location.DoesNotExist:
            self.respond("Sorry, I don't know about a location with code %(code)s. Please check your code and try again.",
                         code=clinic_code)
Пример #7
0
    def handle(self, text):
        b = InputCleaner()
        if not is_eligible_for_results(self.msg.connection):
            self.respond(self.NOT_ELIGIBLE)
            return
        if not text or not text.strip():
            return
        clinic_code = text.split()[0]
        #staff with zeros in case someone just send PP or PPDD
        if b.try_replace_oil_with_011(clinic_code[0:6]).isdigit():
            clinic_code = clinic_code + "00000"
            clinic_code = clinic_code[0:6]
        district_facilities = None
        province_facilities = None
        try:
            location = Location.objects.get(slug__iexact=clinic_code)
            if location.type.slug == 'districts':
                district_facilities = Location.objects.filter(parent=location,
                                                              type__slug__in=
                                                              const.CLINIC_SLUGS)
            elif location.type.slug == 'provinces':
                province_facilities = Location.objects.filter(parent__parent=
                                                              location,
                                                              type__slug__in=
                                                              const.CLINIC_SLUGS)

        except Location.DoesNotExist:
            # maybe it's a district like 403000
            try:
                clinic_code = clinic_code.replace('000', '0')
                district_facilities = Location.objects.filter(slug__startswith=
                                                              clinic_code,
                                                              type__slug__in=
                                                              const.CLINIC_SLUGS)
                location = district_facilities[0].parent
            except IndexError:
                #maybe it's a province like 400000
                try:
                    clinic_code = clinic_code.replace('000', '0')
                    province_facilities = Location.objects.filter(slug__startswith=
                                                                  clinic_code,
                                                                  type__slug__in=
                                                                  const.CLINIC_SLUGS)
                    location = province_facilities[0].parent.parent
                    
                except IndexError:
                    self.respond("Sorry, I don't know about a location with code %(code)s. Please check your code and try again.",
                                 code=clinic_code)
                    return
        text = text.strip()
        text = b.remove_double_spaces(text)
        today = datetime.datetime.today()
        try:
            month = int(b.words_to_digits(text.split()[1][0:3]))
        except (IndexError, TypeError):
            month = today.month
        if month not in range(1, 13):
            month = today.month
        startdate = datetime.datetime(today.year, month, 1)
        if month == 12:
            enddate = datetime.datetime(today.year, 12, 31)
        else:
            enddate = datetime.datetime(today.year, month + 1, 1) - datetime.timedelta(seconds=1)
        report_values = self.get_facility_report(location, startdate, enddate,
                                                 district_facilities,
                                                 province_facilities)

        rpt_header = "SENT RESULTS\n%s\n%s to %s" % (location.name,
                                                     startdate.strftime("%d/%m/%Y"), enddate.strftime("%d/%m/%Y"))
        rpt_data = '\n'.join(key + ";" + str(value) for key, value in
                             report_values.items())
        msg = rpt_header + '\n' + rpt_data         
        
        self.respond(msg)
Пример #8
0
    def handle(self, text):
        b = InputCleaner()
        if not is_eligible_for_results(self.msg.connection):
            self.respond(self.NOT_ELIGIBLE)
            return
        if not text or not text.strip():
            return
        clinic_code = text.split()[0]
        #staff with zeros in case someone just send PP or PPDD
        if b.try_replace_oil_with_011(clinic_code[0:6]).isdigit():
            clinic_code = clinic_code + "00000"
            clinic_code = clinic_code[0:6]
        district_facilities = None
        province_facilities = None
        try:
            location = Location.objects.get(slug__iexact=clinic_code)
            if location.type.slug == 'districts':
                district_facilities = Location.objects.filter(
                    parent=location, type__slug__in=const.CLINIC_SLUGS)
            elif location.type.slug == 'provinces':
                province_facilities = Location.objects.filter(
                    parent__parent=location, type__slug__in=const.CLINIC_SLUGS)

        except Location.DoesNotExist:
            # maybe it's a district like 403000
            try:
                clinic_code = clinic_code.replace('000', '0')
                district_facilities = Location.objects.filter(
                    slug__startswith=clinic_code,
                    type__slug__in=const.CLINIC_SLUGS)
                location = district_facilities[0].parent
            except IndexError:
                #maybe it's a province like 400000
                try:
                    clinic_code = clinic_code.replace('000', '0')
                    province_facilities = Location.objects.filter(
                        slug__startswith=clinic_code,
                        type__slug__in=const.CLINIC_SLUGS)
                    location = province_facilities[0].parent.parent

                except IndexError:
                    self.respond(
                        "Sorry, I don't know about a location with code %(code)s. Please check your code and try again.",
                        code=clinic_code)
                    return
        text = text.strip()
        text = b.remove_double_spaces(text)
        today = datetime.datetime.today()
        try:
            month = int(b.words_to_digits(text.split()[1][0:3]))
        except (IndexError, TypeError):
            month = today.month
        if month not in range(1, 13):
            month = today.month
        startdate = datetime.datetime(today.year, month, 1)
        if month == 12:
            enddate = datetime.datetime(today.year, 12, 31)
        else:
            enddate = datetime.datetime(today.year, month + 1,
                                        1) - datetime.timedelta(seconds=1)
        report_values = self.get_facility_report(location, startdate, enddate,
                                                 district_facilities,
                                                 province_facilities)

        rpt_header = "SENT RESULTS\n%s\n%s to %s" % (
            location.name, startdate.strftime("%d/%m/%Y"),
            enddate.strftime("%d/%m/%Y"))
        rpt_data = '\n'.join(key + ";" + str(value)
                             for key, value in report_values.items())
        msg = rpt_header + '\n' + rpt_data

        self.respond(msg)
Пример #9
0
    def check_message_valid_and_clean(self, text):
        '''
        Checks the message for general validity (correct pin length, number of keywords, etc) and
        returns False if message is somehow invalid (after firing off a useful response message)

        Returns cleaned message in tokenized format (tuple)
        '''
        original_text = text
        cleaner = InputCleaner()

        text = text.strip()
        text = cleaner.remove_double_spaces(text)
        if len(text) < (self.PIN_LENGTH + self.MIN_CLINIC_CODE_LENGTH +
                        self.MIN_NAME_LENGTH + 1):
            self.mulformed_msg_help()
            return False

        #signed pin
        if text[-5:-4] == '-' or text[-5:-4] == '+':
            self.invalid_pin(text[-5:])
            return False
        #too long pin
        if ' ' in text and text[1 + text.rindex(' '):].isdigit() and len(
                text[1 + text.rindex(' '):]) > self.PIN_LENGTH:
            self.invalid_pin(text[1 + text.rindex(' '):])
            return False
        #non-white space before pin
        if text[-5:-4] != ' ' and text[-4:-3] != ' ':
            self.respond(
                "Sorry, you should put a space before your pin. "
                "Please make sure your code is a %s-digit number like %s. "
                "Send JOIN <LOCATION CODE> <YOUR NAME> <SECURITY CODE>." %
                (self.PIN_LENGTH, ''.join(
                    str(i) for i in range(1,
                                          int(self.PIN_LENGTH) + 1))))
            return False
        #reject invalid pin
        user_pin = text[-4:]
        if not user_pin:
            self.help()
            return False
        elif len(user_pin) < 4:
            self.invalid_pin(user_pin)
            return False
        elif not user_pin.isdigit():
            self.invalid_pin(user_pin)
            return False

        group = self.PATTERN.search(original_text)
        if group is None:
            self.mulformed_msg_help()
            return False

        tokens = group.groups()
        if not tokens:
            self.mulformed_msg_help()
            return False
        #sanitize!

        group = self.PATTERN.search(text)

        tokens = group.groups()
        tokens = list(tokens)
        tokens[0] = tokens[0].strip()  #location code
        tokens[2] = tokens[2].title().strip()  #name
        tokens[4] = tokens[4].strip()  #pin

        #more error checking
        if len(tokens[4]) != self.PIN_LENGTH:
            self.respond(self.INVALID_PIN)
            return False
        if not tokens[2]:
            self.respond("Sorry, you must provide a name to register. %s" %
                         self.HELP_TEXT)
            return False
        elif len(tokens[2]) < self.MIN_NAME_LENGTH:
            self.respond(
                "Sorry, you must provide a valid name to register. %s" %
                self.HELP_TEXT)
            return False

        return tuple(tokens)
Пример #10
0
    def handle(self, text):
        b = InputCleaner()
        if not is_eligible_for_results(self.msg.connection):
            # essentially checking for an active clinic_worker
            self.respond(self.INELIGIBLE)
            return

        text = text.strip()
        text = b.remove_double_spaces(text)
        worker = self.msg.contact
        location = worker.location
        if location.type == const.get_zone_type():
            location = location.parent
        cba = None

        # we expect phone numbers like +260977123456, 0977123456, 977123456
        # (a phone number is unique to each cba at a clinic)
        if text[1:].isdigit() and len(text) >= self.MIN_PHONE_LENGTH:
            try:
                cba = \
                Contact.active.get(connection__identity__endswith=text,
                                   location__parent=location,
                                   types=const.get_cba_type())
            except Contact.DoesNotExist:
                self.respond('The phone number %(phone)s does not belong to any'
                             ' CBA at %(clinic)s. Make sure you typed it '
                             'correctly', phone=text, clinic=location)
            # we do not expect this to happen. phone number is excpected to be
            # unique (>=9 chars) project wide
            except Contact.MultipleObjectsReturned:
                logger.warning("Bug. phone number %s is used by multiple cba's "
                               "at same clinic" % text)

                self.respond("Sorry %(name)s, the CBA with phone number %(phone)s"
                             " could not be deregistered. This matter will be"
                             " followed up by Support Staff immediately",
                             name=worker.name, phone=text)

                msg = (self.FOLLOWUP_MESSAGE % (text, worker.name,
                       worker.default_connection.identity,
                       location.name))
                self.notify_help_admins(msg)
                return

        if not cba:
            cbas = \
            Contact.active.filter(name__icontains=text,
                                  location__parent=location,
                                  types=const.get_cba_type())
            if not cbas:
                self.respond('The name %(name)s does not belong to any'
                             ' CBA at %(clinic)s. Make sure you typed it '
                             'correctly', name=text,
                             clinic=location)
                return
            if len(cbas) == 1:
                cba = cbas[0]
            elif len(cbas) < 5:
                self.respond("Try sending REMOVE <CBA_PHONE_NUMBER>. Which "
                             + "CBA did you mean? %(cbas)s", cbas=' or '.join(
                             cba.name + ":" + cba.default_connection.identity
                             for cba in cbas))
                return
            else:
                self.respond("There are %(len)s CBA's who's names match %(name)s"
                             + " at %(clinic)s. Try to use the phone number "
                             + "instead", len=len(cbas), name=text,
                             clinic=location.name)
                return
        if cba:
            cba.is_active = False
            cba.save()
            self.respond("You have successfully deregistered %(name)s:"
                         + "%(phone)s of zone %(zone)s at %(clinic)s",
                         name=cba.name, phone=cba.default_connection.identity,
                         zone=cba.location.name, clinic=location.name)
            msg = ("%s:%s has deregistered %s:%s of zone %s at %s" %
                   (worker.name,
                   worker.default_connection.identity,
                   cba.name,
                   cba.default_connection.identity,
                   cba.location.name,
                   location.name))
            self.notify_help_admins(msg)
Пример #11
0
    def check_message_valid_and_clean(self, text):
        '''
        Checks the message for general validity (correct pin length, number of keywords, etc) and
        returns False if message is somehow invalid (after firing off a useful response message)

        Returns cleaned message in tokenized format (tuple)
        '''
        original_text = text
        cleaner = InputCleaner()

        text = text.strip()
        text = cleaner.remove_double_spaces(text)
        if len(text) < (self.PIN_LENGTH + self.MIN_CLINIC_CODE_LENGTH + self.MIN_NAME_LENGTH + 1):
            self.mulformed_msg_help()
            return False

        #signed pin
        if text[-5:-4] == '-' or text[-5:-4] == '+':
            self.invalid_pin(text[-5:])
            return False
        #too long pin
        if ' ' in text and text[1 + text.rindex(' '):].isdigit() and len(text[1 + text.rindex(' '):]) > self.PIN_LENGTH:
            self.invalid_pin(text[1 + text.rindex(' '):])
            return False
        #non-white space before pin
        if text[-5:-4] != ' ' and text[-4:-3] != ' ':
            self.respond("Sorry, you should put a space before your pin. "
                         "Please make sure your code is a %s-digit number like %s. "
                         "Send JOIN <LOCATION CODE> <YOUR NAME> <SECURITY CODE>." % (
                         self.PIN_LENGTH, ''.join(str(i) for i in range(1, int(self.PIN_LENGTH) + 1))))
            return False
        #reject invalid pin
        user_pin = text[-4:]
        if not user_pin:
            self.help()
            return False
        elif len(user_pin) < 4:
            self.invalid_pin(user_pin)
            return False
        elif not user_pin.isdigit():
            self.invalid_pin(user_pin)
            return False

        group = self.PATTERN.search(original_text)
        if group is None:
            self.mulformed_msg_help()
            return False

        tokens = group.groups()
        if not tokens:
            self.mulformed_msg_help()
            return False
        #sanitize!

        group = self.PATTERN.search(text)

        tokens = group.groups()
        tokens = list(tokens)
        tokens[0] = tokens[0].strip() #location code
        tokens[2] = tokens[2].title().strip() #name
        tokens[4] = tokens[4].strip() #pin


        #more error checking
        if len(tokens[4]) != self.PIN_LENGTH:
            self.respond(self.INVALID_PIN)
            return False
        if not tokens[2]:
            self.respond("Sorry, you must provide a name to register. %s" % self.HELP_TEXT)
            return False
        elif len(tokens[2]) < self.MIN_NAME_LENGTH:
            self.respond("Sorry, you must provide a valid name to register. %s" % self.HELP_TEXT)
            return False

        return tuple(tokens)
Пример #12
0
    def handle(self, text):
        b = InputCleaner()
        if not is_eligible_for_results(self.msg.connection):
            # essentially checking for an active clinic_worker
            self.respond(self.INELIGIBLE)
            return

        text = text.strip()
        text = b.remove_double_spaces(text)
        worker = self.msg.contact
        location = worker.location
        if location.type == const.get_zone_type():
            location = location.parent
        cba = None

        # we expect phone numbers like +260977123456, 0977123456, 977123456
        # (a phone number is unique to each cba at a clinic)
        if text[1:].isdigit() and len(text) >= self.MIN_PHONE_LENGTH:
            try:
                cba = \
                Contact.active.get(connection__identity__endswith=text,
                                   location__parent=location,
                                   types=const.get_cba_type())
            except Contact.DoesNotExist:
                self.respond(
                    'The phone number %(phone)s does not belong to any'
                    ' CBA at %(clinic)s. Make sure you typed it '
                    'correctly',
                    phone=text,
                    clinic=location)
            # we do not expect this to happen. phone number is excpected to be
            # unique (>=9 chars) project wide
            except Contact.MultipleObjectsReturned:
                logger.warning(
                    "Bug. phone number %s is used by multiple cba's "
                    "at same clinic" % text)

                self.respond(
                    "Sorry %(name)s, the CBA with phone number %(phone)s"
                    " could not be deregistered. This matter will be"
                    " followed up by Support Staff immediately",
                    name=worker.name,
                    phone=text)

                msg = (self.FOLLOWUP_MESSAGE %
                       (text, worker.name, worker.default_connection.identity,
                        location.name))
                self.notify_help_admins(msg)
                return

        if not cba:
            cbas = \
            Contact.active.filter(name__icontains=text,
                                  location__parent=location,
                                  types=const.get_cba_type())
            if not cbas:
                self.respond(
                    'The name %(name)s does not belong to any'
                    ' CBA at %(clinic)s. Make sure you typed it '
                    'correctly',
                    name=text,
                    clinic=location)
                return
            if len(cbas) == 1:
                cba = cbas[0]
            elif len(cbas) < 5:
                self.respond("Try sending REMOVE <CBA_PHONE_NUMBER>. Which " +
                             "CBA did you mean? %(cbas)s",
                             cbas=' or '.join(cba.name + ":" +
                                              cba.default_connection.identity
                                              for cba in cbas))
                return
            else:
                self.respond(
                    "There are %(len)s CBA's who's names match %(name)s" +
                    " at %(clinic)s. Try to use the phone number " + "instead",
                    len=len(cbas),
                    name=text,
                    clinic=location.name)
                return
        if cba:
            cba.is_active = False
            cba.save()
            self.respond("You have successfully deregistered %(name)s:" +
                         "%(phone)s of zone %(zone)s at %(clinic)s",
                         name=cba.name,
                         phone=cba.default_connection.identity,
                         zone=cba.location.name,
                         clinic=location.name)
            msg = ("%s:%s has deregistered %s:%s of zone %s at %s" %
                   (worker.name, worker.default_connection.identity, cba.name,
                    cba.default_connection.identity, cba.location.name,
                    location.name))
            self.notify_help_admins(msg)
Пример #13
0
class TestApp(TestScript):

    ic = InputCleaner()

    def testSoundEx(self):
        self.assertEqual(self.ic.soundex('thri'), self.ic.soundex('three'))

    def testWordsToDigits(self):
        self.assertEqual(2, self.ic.words_to_digits('two'))
        self.assertEqual(2, self.ic.words_to_digits('too'))
        self.assertEqual(302, self.ic.words_to_digits('thri hundred two'))
        self.assertEqual(302, self.ic.words_to_digits('thri hundred and two'))
        self.assertEqual(26, self.ic.words_to_digits('twenti six'))
        self.assertEqual(8002,
                         self.ic.words_to_digits('Eight thousand and two'))
        self.assertEqual(
            2001082,
            self.ic.words_to_digits(
                '2 milion one thouzand Eighty too samples'))

    def testReplaceoilWith011(self):
        self.assertEqual('00111', self.ic.try_replace_oil_with_011('oOiIl'))
        self.assertEqual('403012', self.ic.try_replace_oil_with_011('4o3oi2'))

    def testRemoveDoubleSpaces(self):
        self.assertEqual(
            'request 10 for db samples',
            self.ic.remove_double_spaces(
                'request  10    for  db      samples'))

    def testDigitToWord(self):
        self.assertEqual('One', self.ic.digit_to_word(1))
        self.assertEqual('Two', self.ic.digit_to_word(2))
        self.assertEqual('Thirty', self.ic.digit_to_word(30))
        self.assertEqual(None, self.ic.digit_to_word(31))

    def testLdistance(self):
        self.assertEqual(0, self.ic.ldistance('pea', 'PeA'))
        self.assertEqual(1, self.ic.ldistance('peac', 'PeA'))
        self.assertEqual(1, self.ic.ldistance('pea', 'PeAc'))
        self.assertEqual(1, self.ic.ldistance('pea', 'PeAc'))
        self.assertEqual(4, self.ic.ldistance('trev', 'nanc'))

    def testConditonalStringCleaning(self):
        """
        Tests string cleaning based on keywords
        """

        self.assertEqual(0, Contact.objects.count())
        ctr = LocationType.objects.create(slug=const.CLINIC_SLUGS[0])
        kdh = Location.objects.create(name="Kafue District Hospital",
                                      slug="kdh",
                                      type=ctr)
        Location.objects.create(name="Central Clinic", slug="403012", type=ctr)

        #in JOIN clean separators including '/'
        script = """
        0979565992 > join 403012/jichael,mackson;1111
        0979565992 < Hi Jichael Mackson, thanks for registering for Results160 from Central Clinic. Your PIN is 1111. Reply with keyword 'HELP' if this is incorrect
        """
        self.runScript(script)

        #in AGENT clean separators including '/'
        script = """
        cba1 > agent 403012/2,peter;phiri
        cba1 < Thank you Peter Phiri! You have successfully registered as a RemindMi Agent for zone 2 of Central Clinic.
        cba2 > agent 403012/2,james;banda
        cba2 < Thank you James Banda! You have successfully registered as a RemindMi Agent for zone 2 of Central Clinic.
        """
        self.runScript(script)

        # in RESULT don't clean '/'
        script = """
        0979565992 > results 403012/10
        0979565992 < There are currently no results available for 403012/10. Please check if the SampleID is correct or sms HELP if you have been waiting for 2 months or more
        """
        self.runScript(script)

        # in broadcasts don't clean
        script = """
        cba1 > clinic 403012/10. Not 402012/09;
        0979565992 < 403012/10. Not 402012/09; [from Peter Phiri to CLINIC]
        cba1 > cba dont't filter , or / or ; or * or + or - in broadcasts
        cba2 < dont't filter , or / or ; or * or + or - in broadcasts [from Peter Phiri to CBA]
        """
        self.runScript(script)

        script = """
        0979565993 > join 403012/princess,obama;1111
        0979565993 < Hi Princess Obama, thanks for registering for Results160 from Central Clinic. Your PIN is 1111. Reply with keyword 'HELP' if this is incorrect
        """
        self.runScript(script)

        admin = Contact.active.get(connection__identity='0979565993')
        admin.is_help_admin = True
        admin.save()

        script = """
        0979565993 > blaster in blaster we dont clean , or / or ; or * or + or -
        0979565992 < in blaster we dont clean , or / or ; or * or + or - [from Princess Obama to Mwana Users]
        cba1 < in blaster we dont clean , or / or ; or * or + or - [from Princess Obama to Mwana Users]
        cba2 < in blaster we dont clean , or / or ; or * or + or - [from Princess Obama to Mwana Users]
        """
        self.runScript(script)