Ejemplo n.º 1
0
    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)

        reminder = request.POST.get('reminder')
        phone_number = context.get('phone_number')

        if reminder and phone_number:
            phone_number = clean_phone_number(phone_number)
            v = VerifiedNumber.by_phone(phone_number, include_pending=True)
            if v and v.verified:
                user = v.owner
                if reminder == 'first_soh':
                    first_soh_process_user(user, test=True)
                elif reminder == 'second_soh':
                    now = datetime.datetime.utcnow()
                    date = now - datetime.timedelta(days=5)
                    second_soh_process_user(user, date, test=True)
                elif reminder == 'third_soh':
                    third_soh_process_users_and_facilities([user], [user.location.sql_location], test=True)
                elif reminder == 'stockout':
                    stockout_process_user(user, test=True)
                elif reminder == 'rrirv':
                    rrirv_process_user(user, test=True)
                elif reminder == 'visit_website':
                    visit_website_process_user(user, test=True)
        messages.success(request, "Reminder was sent successfully")
        return self.get(request, *args, **kwargs)
Ejemplo n.º 2
0
def validate_row(row, domain, data_cols):
    """pre-validate the information in a particular import row: valid location,
    reporting user, and data formats
    """
    # identify location
    loc_code = row.get('outlet_code') or row.get('site_code')
    row['loc'] = get_supply_point(domain, loc_code)['case']
    if row['loc'] is None:
        set_error(row, 'ERROR location code is invalid')
        return

    # identify user
    phone = row.get('phone')
    owner = None
    if phone:
        vn = VerifiedNumber.by_phone(phone)
        if not vn:
            set_error(row, 'ERROR phone number is not verified with any user')
            return
        owner = vn.owner
        row['phone'] = strip_plus(phone)

    username = row.get('reporter')
    if username:
        user = CouchUser.get_by_username('%s@%s.commcarehq.org' %
                                         (username, domain))
        if not user:
            set_error(row, 'ERROR reporter user does not exist')
            return

    if owner:
        if user and user._id != owner._id:
            set_error(row, 'ERROR phone number does not belong to user')
            return
        user = owner
    row['user'] = user

    # validate other fields

    try:
        row['timestamp'] = datetime.strptime(row['date'],
                                             '%Y-%m-%d')  # TODO: allow time?
    except ValueError:
        set_error(row, 'ERROR invalid date format')
        return

    for k in data_cols:
        val = row[k]
        if val:
            try:
                int(val)
            except ValueError:
                set_error(
                    row,
                    'ERROR invalid data value "%s" in column "%s"' % (val, k))
                return

    if all(not row[k] for k in data_cols):
        set_error(row, 'ERROR stock report is empty')
        return
Ejemplo n.º 3
0
def initiate_sms_verification_workflow(contact, phone_number):
    # For now this is only applicable to mobile workers
    assert isinstance(contact, CommCareUser)

    logged_event = MessagingEvent.get_current_verification_event(
        contact.domain, contact.get_id, phone_number)

    with CriticalSection(['verifying-phone-number-%s' % phone_number]):
        vn = VerifiedNumber.by_phone(phone_number, include_pending=True)
        if vn:
            if vn.owner_id != contact._id:
                return VERIFICATION__ALREADY_IN_USE
            if vn.verified:
                return VERIFICATION__ALREADY_VERIFIED
            else:
                result = VERIFICATION__RESENT_PENDING
        else:
            contact.save_verified_number(contact.domain, phone_number, False)
            result = VERIFICATION__WORKFLOW_STARTED
            # Always create a new event when the workflow starts
            if logged_event:
                logged_event.status = MessagingEvent.STATUS_NOT_COMPLETED
                logged_event.save()
            logged_event = MessagingEvent.create_verification_event(contact.domain, contact)

        if not logged_event:
            logged_event = MessagingEvent.create_verification_event(contact.domain, contact)

        send_verification(contact.domain, contact, phone_number, logged_event)
        return result
Ejemplo n.º 4
0
    def validate_sms_users(self):
        for sms_user in iterate_over_api_objects(self.endpoint.get_smsusers):
            description = ""
            user = CommCareUser.get_by_username(self.get_username(sms_user)[0])
            if not user:
                description = "Not exists"
                EWSMigrationProblem.objects.create(
                    domain=self.domain,
                    external_id=sms_user.id,
                    object_type='smsuser',
                    description=description
                )
                continue

            phone_numbers = {
                apply_leniency(connection.phone_number) for connection in sms_user.phone_numbers
            }

            if phone_numbers - set(user.phone_numbers):
                description += "Invalid phone numbers, "

            phone_to_backend = {
                connection.phone_number: connection.backend
                for connection in sms_user.phone_numbers
            }

            default_phone_number = [
                connection.phone_number for connection in sms_user.phone_numbers if connection.default
            ]

            default_phone_number = default_phone_number[0] if default_phone_number else None

            if default_phone_number and (apply_leniency(default_phone_number) != user.default_phone_number):
                description += "Invalid default phone number, "

            for phone_number in user.phone_numbers:
                vn = VerifiedNumber.by_phone(phone_number)
                if not vn or vn.owner_id != user.get_id:
                    description += "Phone number not verified, "
                else:
                    backend = phone_to_backend.get(phone_number)
                    if backend == 'message_tester' and vn.backend_id != 'MOBILE_BACKEND_TEST' \
                            or (backend != 'message_tester' and vn.backend_id):
                        description += "Invalid backend, "

            if description:
                migration_problem, _ = EWSMigrationProblem.objects.get_or_create(
                    domain=self.domain,
                    object_id=user.get_id,
                    object_type='smsuser'
                )
                migration_problem.external_id = sms_user.id
                migration_problem.description = description.rstrip(' ,')
                migration_problem.save()
            else:
                EWSMigrationProblem.objects.filter(
                    domain=self.domain,
                    external_id=sms_user.id,
                    object_type='smsuser'
                ).delete()
Ejemplo n.º 5
0
def process_incoming(msg, delay=True):
    v = VerifiedNumber.by_phone(msg.phone_number, include_pending=True)

    if v is not None and v.verified:
        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        msg.save()

    if msg.domain_scope:
        # only process messages for phones known to be associated with this domain
        if v is None or v.domain != msg.domain_scope:
            raise DomainScopeValidationError(
                'Attempted to simulate incoming sms from phone number not ' \
                'verified with this domain'
            )
    create_billable_for_sms(msg, msg.backend_api, delay=delay)

    if v is not None and v.verified:
        for h in settings.SMS_HANDLERS:
            try:
                handler = to_function(h)
            except:
                logging.exception('error loading sms handler: %s' % h)
                continue

            try:
                was_handled = handler(v, msg.text, msg=msg)
            except Exception, e:
                logging.exception('unhandled error in sms handler %s for message [%s]: %s' % (h, msg._id, e))
                was_handled = False

            if was_handled:
                break
Ejemplo n.º 6
0
def process_incoming(msg, delay=True):
    v = VerifiedNumber.by_phone(msg.phone_number, include_pending=True)

    if v is not None and v.verified:
        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        msg.save()

    if msg.domain_scope:
        # only process messages for phones known to be associated with this domain
        if v is None or v.domain != msg.domain_scope:
            raise DomainScopeValidationError(
                'Attempted to simulate incoming sms from phone number not ' \
                'verified with this domain'
            )

    if v is not None and v.verified:
        for h in settings.SMS_HANDLERS:
            try:
                handler = to_function(h)
            except:
                notify_exception(None,
                                 message=('error loading sms handler: %s' % h))
                continue

            try:
                was_handled = handler(v, msg.text, msg=msg)
            except Exception, e:
                log_sms_exception(msg)
                was_handled = False

            if was_handled:
                break
Ejemplo n.º 7
0
def process_verification(phone_number, msg, backend_id=None):
    v = VerifiedNumber.by_phone(phone_number, True)
    if not v:
        return

    if not verification_response_ok(msg.text):
        return

    msg.domain = v.domain
    msg.couch_recipient_doc_type = v.owner_doc_type
    msg.couch_recipient = v.owner_id
    msg.save()

    if not domain_has_privilege(msg.domain, privileges.INBOUND_SMS):
        return

    if backend_id:
        backend = MobileBackend.load(backend_id)
    else:
        backend = MobileBackend.auto_load(phone_number, v.domain)

    # i don't know how to dynamically instantiate this object, which may be any number of doc types...
    #owner = CommCareMobileContactMixin.get(v.owner_id)
    assert v.owner_doc_type == 'CommCareUser'
    owner = CommCareUser.get(v.owner_id)

    v = owner.save_verified_number(v.domain, phone_number, True, backend.name)
    with localize(owner.language):
        send_sms_to_verified_number(v, _(CONFIRM))
Ejemplo n.º 8
0
def initiate_sms_verification_workflow(contact, phone_number):
    # For now this is only applicable to mobile workers
    assert isinstance(contact, CommCareUser)

    logged_event = MessagingEvent.get_current_verification_event(
        contact.domain, contact.get_id, phone_number)

    with CriticalSection(['verifying-phone-number-%s' % phone_number]):
        vn = VerifiedNumber.by_phone(phone_number, include_pending=True)
        if vn:
            if vn.owner_id != contact._id:
                return VERIFICATION__ALREADY_IN_USE
            if vn.verified:
                return VERIFICATION__ALREADY_VERIFIED
            else:
                result = VERIFICATION__RESENT_PENDING
        else:
            contact.save_verified_number(contact.domain, phone_number, False)
            result = VERIFICATION__WORKFLOW_STARTED
            # Always create a new event when the workflow starts
            if logged_event:
                logged_event.status = MessagingEvent.STATUS_NOT_COMPLETED
                logged_event.save()
            logged_event = MessagingEvent.create_verification_event(
                contact.domain, contact)

        if not logged_event:
            logged_event = MessagingEvent.create_verification_event(
                contact.domain, contact)

        send_verification(contact.domain, contact, phone_number, logged_event)
        return result
Ejemplo n.º 9
0
 def get_context_data(self, **kwargs):
     context = super(BaseRemindersTester, self).get_context_data(**kwargs)
     context['phone_number'] = kwargs.get('phone_number')
     verified_number = VerifiedNumber.by_phone(context['phone_number'])
     context['phone_user'] = CommCareUser.get(
         verified_number.owner_id) if verified_number else None
     return context
Ejemplo n.º 10
0
def process_verification(phone_number, msg, backend_id=None):
    v = VerifiedNumber.by_phone(phone_number, True)
    if not v:
        return

    if not verification_response_ok(msg.text):
        return

    msg.domain = v.domain
    msg.couch_recipient_doc_type = v.owner_doc_type
    msg.couch_recipient = v.owner_id
    msg.save()

    if backend_id:
        backend = MobileBackend.load(backend_id)
    else:
        backend = MobileBackend.auto_load(phone_number, v.domain)

    # i don't know how to dynamically instantiate this object, which may be any number of doc types...
    #owner = CommCareMobileContactMixin.get(v.owner_id)
    assert v.owner_doc_type == 'CommCareUser'
    owner = CommCareUser.get(v.owner_id)

    v = owner.save_verified_number(v.domain, phone_number, True, backend.name)
    with localize(owner.language):
        send_sms_to_verified_number(v, _(CONFIRM))
Ejemplo n.º 11
0
def incoming(phone_number, text, backend_api, timestamp=None, domain_scope=None, delay=True):
    """
    entry point for incoming sms

    phone_number - originating phone number
    text - message content
    backend_api - backend ID of receiving sms backend
    timestamp - message received timestamp; defaults to now (UTC)
    domain_scope - if present, only messages from phone numbers that can be
      definitively linked to this domain will be processed; others will be
      dropped (useful to provide security when simulating incoming sms)
    """
    phone_number = clean_phone_number(phone_number)
    v = VerifiedNumber.by_phone(phone_number, include_pending=True)
    if domain_scope:
        # only process messages for phones known to be associated with this domain
        if v is None or v.domain != domain_scope:
            raise RuntimeError("attempted to simulate incoming sms from phone number not verified with this domain")

    # Log message in message log
    msg = SMSLog(
        phone_number=phone_number,
        direction=INCOMING,
        date=timestamp or datetime.utcnow(),
        text=text,
        backend_api=backend_api,
    )
    if v is not None and v.verified:
        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
    msg.save()

    create_billable_for_sms(msg, backend_api, delay=delay)

    if v is not None and v.verified:
        for h in settings.SMS_HANDLERS:
            try:
                handler = to_function(h)
            except:
                logging.exception("error loading sms handler: %s" % h)
                continue

            try:
                was_handled = handler(v, text)
            except:
                logging.exception("unhandled error in sms handler %s for message [%s]" % (h, text))
                was_handled = False

            if was_handled:
                break
    else:
        if not process_sms_registration(msg):
            import verify

            verify.process_verification(phone_number, text)

    return msg
Ejemplo n.º 12
0
    def handle(self):
        words = self.args
        if len(words) < 2 or len(words) > 3:
            self.respond(REGISTER_HELP)
            return

        name = words[0]
        code = words[1]
        params = {
            "msd_code": code
        }
        if not self.user:
            domains = [config.domain for config in ILSGatewayConfig.get_all_configs()]
            for domain in domains:
                loc = self._get_facility_location(domain, code)
                if not loc:
                    continue

                splited_name = name.split(' ', 1)
                first_name = splited_name[0]
                last_name = splited_name[1] if len(splited_name) > 1 else ""
                clean_name = name.replace(' ', '.')
                username = "******" % (clean_name, domain)
                password = User.objects.make_random_password()
                user = CommCareUser.create(domain=domain, username=username, password=password,
                                           commit=False)
                user.first_name = first_name
                user.last_name = last_name

                if len(words) == 3:
                    user.user_data = {
                        'role': words[2]
                    }

                try:
                    user.set_default_phone_number(self.msg.phone_number.replace('', ''))
                    user.save_verified_number(domain, self.msg.phone_number.replace('', ''), True, self.msg.backend_api)
                except PhoneNumberInUseException as e:
                    v = VerifiedNumber.by_phone(self.msg.phone_number, include_pending=True)
                    v.delete()
                    user.save_verified_number(domain, self.msg.phone_number.replace('', ''), True, self.msg.backend_api)
                except CommCareUser.Inconsistent:
                    continue

                user.language = Languages.DEFAULT

                params.update({
                    'sdp_name': loc.name,
                    'contact_name': name
                })

                dm = user.get_domain_membership(domain)
                dm.location_id = loc._id
                user.save()
                add_location(user, loc._id)

        self.respond(REGISTRATION_CONFIRM, **params)
Ejemplo n.º 13
0
def validate_row(row, domain, data_cols):
    """pre-validate the information in a particular import row: valid location,
    reporting user, and data formats
    """
    # identify location
    loc_code = row.get('outlet_code') or row.get('site_code')
    row['loc'] = get_supply_point(domain, loc_code)['case']
    if row['loc'] is None:
        set_error(row, 'ERROR location code is invalid')
        return

    # identify user
    phone = row.get('phone')
    owner = None
    if phone:
        vn = VerifiedNumber.by_phone(phone)
        if not vn:
            set_error(row, 'ERROR phone number is not verified with any user')
            return
        owner = vn.owner
        row['phone'] = strip_plus(phone)

    username = row.get('reporter')
    if username:
        user = CouchUser.get_by_username('%s@%s.commcarehq.org' % (username, domain))
        if not user:
            set_error(row, 'ERROR reporter user does not exist')
            return

    if owner:
        if user and user._id != owner._id:
            set_error(row, 'ERROR phone number does not belong to user')
            return
        user = owner
    row['user'] = user

    # validate other fields

    try:
        row['timestamp'] = datetime.strptime(row['date'], '%Y-%m-%d') # TODO: allow time?
    except ValueError:
        set_error(row, 'ERROR invalid date format')
        return

    for k in data_cols:
        val = row[k]
        if val:
            try:
                int(val)
            except ValueError:
                set_error(row, 'ERROR invalid data value "%s" in column "%s"' % (val, k))
                return

    if all(not row[k] for k in data_cols):
        set_error(row, 'ERROR stock report is empty')
        return
Ejemplo n.º 14
0
def process_incoming(msg, delay=True):
    v = VerifiedNumber.by_phone(msg.phone_number, include_pending=True)

    if v is not None and v.verified:
        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        contact = v.owner
        if isinstance(contact, CommCareUser) and hasattr(contact, 'location_id'):
            msg.location_id = contact.location_id
        msg.save()

    if msg.domain_scope:
        # only process messages for phones known to be associated with this domain
        if v is None or v.domain != msg.domain_scope:
            raise DomainScopeValidationError(
                'Attempted to simulate incoming sms from phone number not ' \
                'verified with this domain'
            )

    can_receive_sms = PhoneNumber.can_receive_sms(msg.phone_number)
    opt_in_keywords, opt_out_keywords = get_opt_keywords(msg)
    if is_opt_message(msg.text, opt_out_keywords) and can_receive_sms:
        if PhoneNumber.opt_out_sms(msg.phone_number):
            metadata = MessageMetadata(ignore_opt_out=True)
            text = get_message(MSG_OPTED_OUT, v, context=(opt_in_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text, metadata=metadata)
            else:
                send_sms(msg.domain, None, msg.phone_number, text, metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords) and not can_receive_sms:
        if PhoneNumber.opt_in_sms(msg.phone_number):
            text = get_message(MSG_OPTED_IN, v, context=(opt_out_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    elif v is not None and v.verified:
        if domain_has_privilege(msg.domain, privileges.INBOUND_SMS):
            for h in settings.SMS_HANDLERS:
                try:
                    handler = to_function(h)
                except:
                    notify_exception(None, message=('error loading sms handler: %s' % h))
                    continue

                try:
                    was_handled = handler(v, msg.text, msg=msg)
                except Exception, e:
                    log_sms_exception(msg)
                    was_handled = False

                if was_handled:
                    break
Ejemplo n.º 15
0
    def assertMatch(self, match, phone_search, suffix_search, owner_id_search):
        lookedup = VerifiedNumber.by_phone(phone_search)
        self.assertEqual(match._id, lookedup._id)
        self.assertEqual(match._rev, lookedup._rev)

        lookedup = VerifiedNumber.by_suffix(suffix_search)
        self.assertEqual(match._id, lookedup._id)
        self.assertEqual(match._rev, lookedup._rev)

        [lookedup] = VerifiedNumber.by_owner_id(owner_id_search)
        self.assertEqual(match._id, lookedup._id)
        self.assertEqual(match._rev, lookedup._rev)
Ejemplo n.º 16
0
 def run_script(self, script):
     commands = self.parse_script(script)
     for command in commands:
         phone_number = command['phone_number']
         v = VerifiedNumber.by_phone(phone_number)
         if command['direction'] == '>':
             incoming(phone_number, command['text'], v.backend_id, domain_scope=v.domain)
         else:
             msg = self.get_last_outbound_sms(v.owner_doc_type, v.owner_id)
             self.assertEqual(msg.text, unicode(command['text']))
             self.assertEqual(strip_plus(msg.phone_number), strip_plus(phone_number))
             msg.delete()
Ejemplo n.º 17
0
 def _reassign_number(self, user, connection):
     v = VerifiedNumber.by_phone(apply_leniency(connection.phone_number), include_pending=True)
     if v.domain in self._get_logistics_domains():
         v.domain = self.domain
         v.owner_doc_type = user.doc_type
         v.owner_id = user.get_id
         backend_id = None
         if connection.backend == 'message_tester':
             backend_id = 'MOBILE_BACKEND_TEST'
         v.backend_id = backend_id
         v.verified = True
         v.save()
Ejemplo n.º 18
0
    def test_phone_numbers_edit(self):
        with open(os.path.join(self.datapath, 'sample_smsusers.json')) as f:
            smsuser = SMSUser(json.loads(f.read())[2])

        self.assertEqual(0, len(CommCareUser.by_domain(TEST_DOMAIN)))
        ilsgateway_smsuser = self.api_object.sms_user_sync(smsuser)
        self.assertListEqual(ilsgateway_smsuser.phone_numbers, ['2222', '3333'])
        vn1 = VerifiedNumber.by_phone('2222')
        vn2 = VerifiedNumber.by_phone('3333')
        self.assertIsNotNone(vn1)
        self.assertIsNotNone(vn2)

        smsuser.phone_numbers = smsuser.phone_numbers[:1]
        ilsgateway_smsuser = self.api_object.sms_user_sync(smsuser)
        self.assertListEqual(ilsgateway_smsuser.phone_numbers, ['2222'])
        vn1 = VerifiedNumber.by_phone('2222')
        vn2 = VerifiedNumber.by_phone('3333')
        self.assertIsNotNone(vn1)
        self.assertIsNone(vn2)

        smsuser.phone_numbers = []
        ilsgateway_smsuser = self.api_object.sms_user_sync(smsuser)
        self.assertListEqual(ilsgateway_smsuser.phone_numbers, [])
        vn1 = VerifiedNumber.by_phone('2222')
        vn2 = VerifiedNumber.by_phone('3333')
        self.assertIsNone(vn1)
        self.assertIsNone(vn2)
Ejemplo n.º 19
0
    def _reassign_number(self, user, connection):
        from custom.ilsgateway import SLAB_DOMAIN

        v = VerifiedNumber.by_phone(apply_leniency(connection.phone_number), include_pending=True)
        if v.domain in self._get_logistics_domains() or v.domain == SLAB_DOMAIN:
            v.domain = self.domain
            v.owner_doc_type = user.doc_type
            v.owner_id = user.get_id
            backend_id = None
            if connection.backend != 'push_backend':
                backend_id = 'MOBILE_BACKEND_TEST'
            v.backend_id = backend_id
            v.verified = True
            v.save()
Ejemplo n.º 20
0
def process_verification(phone_number, msg, backend_id=None):
    v = VerifiedNumber.by_phone(phone_number, True)
    if not v:
        return

    logged_event = MessagingEvent.get_current_verification_event(
        v.domain, v.owner_id, phone_number)

    if not logged_event:
        logged_event = MessagingEvent.create_verification_event(
            v.domain, v.owner)

    subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type, v.owner_id)
    subevent.completed()

    msg.domain = v.domain
    msg.couch_recipient_doc_type = v.owner_doc_type
    msg.couch_recipient = v.owner_id
    msg.messaging_subevent_id = subevent.pk
    msg.save()

    if (not domain_has_privilege(msg.domain, privileges.INBOUND_SMS)
            or not verification_response_ok(msg.text)):
        return

    if backend_id:
        backend = MobileBackend.load(backend_id)
    else:
        backend = MobileBackend.auto_load(phone_number, v.domain)

    assert v.owner_doc_type == 'CommCareUser'
    owner = CommCareUser.get(v.owner_id)

    v = owner.save_verified_number(v.domain, phone_number, True, backend.name)

    logged_event.completed()

    subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type, v.owner_id)

    with localize(owner.language):
        send_sms_to_verified_number(
            v,
            _(CONFIRM),
            metadata=MessageMetadata(messaging_subevent_id=subevent.pk))
        subevent.completed()
Ejemplo n.º 21
0
 def add_language_to_user(self, logistics_sms_user):
     domain_part = "%s.commcarehq.org" % self.domain
     username_part = "%s%d" % (logistics_sms_user.name.strip().replace(' ', '.').lower(),
                               logistics_sms_user.id)
     username = "******" % (username_part[:(128 - (len(domain_part) + 1))], domain_part)
     user = CouchUser.get_by_username(username)
     if user and user.language != logistics_sms_user.language:
         user.language = logistics_sms_user.language
         user.save()
         if user.phone_numbers:
             phone_number = user.phone_numbers[0]
             user.set_default_phone_number(phone_number)
             v = VerifiedNumber.by_phone(phone_number, include_pending=True)
             if v:
                 v.delete()
             user.save_verified_number(self.domain, phone_number, True,
                                       logistics_sms_user.backend)
Ejemplo n.º 22
0
    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)

        reminder = request.POST.get('reminder')
        phone_number = context.get('phone_number')

        if reminder and phone_number:
            phone_number = clean_phone_number(phone_number)
            v = VerifiedNumber.by_phone(phone_number, include_pending=True)
            if v and v.verified:
                user = v.owner
                if not user:
                    return self.get(request, *args, **kwargs)
                reminder_function = self.reminders.get(reminder)
                reminder_function(self.domain, datetime.utcnow(), test_list=[user])
        messages.success(request, "Reminder was sent successfully")
        return self.get(request, *args, **kwargs)
Ejemplo n.º 23
0
    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)

        reminder = request.POST.get('reminder')
        phone_number = context.get('phone_number')

        if reminder and phone_number:
            phone_number = clean_phone_number(phone_number)
            v = VerifiedNumber.by_phone(phone_number, include_pending=True)
            if v and v.verified:
                user = v.owner
                if not user:
                    return self.get(request, *args, **kwargs)
                reminder_function = self.reminders.get(reminder)
                reminder_function(self.domain,
                                  datetime.utcnow(),
                                  test_list=[user])
        messages.success(request, "Reminder was sent successfully")
        return self.get(request, *args, **kwargs)
Ejemplo n.º 24
0
    def test_create_smsuser_with_test_backend(self):
        with open(os.path.join(self.datapath, 'sample_smsusers.json')) as f:
            smsuser = SMSUser(json.loads(f.read())[1])

        self.assertEqual(0, len(CommCareUser.by_domain(TEST_DOMAIN)))
        ilsgateway_smsuser = self.api_object.sms_user_sync(smsuser)
        first_name, last_name = ilsgateway_smsuser.name.split(' ', 1)
        username_part = "%s%d" % (ilsgateway_smsuser.name.strip().replace(' ', '.').lower(), smsuser.id)
        username = "******" % (username_part, TEST_DOMAIN)

        self.assertEqual(username, ilsgateway_smsuser.username)
        self.assertEqual(first_name, ilsgateway_smsuser.first_name)
        self.assertEqual(last_name, ilsgateway_smsuser.last_name)
        self.assertEqual(smsuser.is_active, ilsgateway_smsuser.is_active)
        self.assertEqual(TEST_DOMAIN, ilsgateway_smsuser.get_domains()[0])
        self.assertEqual(ilsgateway_smsuser.default_phone_number, '222')
        verified_number = VerifiedNumber.by_phone(ilsgateway_smsuser.default_phone_number)
        self.assertIsNotNone(verified_number)
        self.assertEqual(verified_number.backend_id, 'MOBILE_BACKEND_TEST')
Ejemplo n.º 25
0
def initiate_sms_verification_workflow(contact, phone_number):
    # For now this is only applicable to mobile workers
    assert isinstance(contact, CommCareUser)

    with CriticalSection(['verifying-phone-number-%s' % phone_number]):
        vn = VerifiedNumber.by_phone(phone_number, include_pending=True)
        if vn:
            if vn.owner_id != contact._id:
                return VERIFICATION__ALREADY_IN_USE
            if vn.verified:
                return VERIFICATION__ALREADY_VERIFIED
            else:
                result = VERIFICATION__RESENT_PENDING
        else:
            contact.save_verified_number(contact.domain, phone_number, False)
            result = VERIFICATION__WORKFLOW_STARTED

        send_verification(contact.domain, contact, phone_number)
        return result
Ejemplo n.º 26
0
    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)

        reminder = request.POST.get('reminder')
        phone_number = context.get('phone_number')

        if reminder and phone_number:
            phone_number = clean_phone_number(phone_number)
            v = VerifiedNumber.by_phone(phone_number, include_pending=True)
            if v and v.verified:
                user = v.owner
                if not user:
                    return self.get(request, *args, **kwargs)
                reminder_function = self.reminders.get(reminder)
                if reminder_function:
                    if reminder == 'third_soh':
                        reminder_function([user], [user.location.sql_location], test=True)
                    else:
                        reminder_function(user, test=True)
        messages.success(request, "Reminder was sent successfully")
        return self.get(request, *args, **kwargs)
Ejemplo n.º 27
0
def process_verification(phone_number, text, backend_id=None):
    v = VerifiedNumber.by_phone(phone_number, True)
    if not v:
        return

    if not verification_response_ok(text):
        return
    
    if backend_id:
        backend = MobileBackend.load(backend_id)
    else:
        backend = MobileBackend.auto_load(phone_number, v.domain)

    # i don't know how to dynamically instantiate this object, which may be any number of doc types...
    #owner = CommCareMobileContactMixin.get(v.owner_id)
    assert v.owner_doc_type == 'CommCareUser'
    owner = CommCareUser.get(v.owner_id)

    owner.save_verified_number(v.domain, phone_number, True, backend._id)

    api.send_sms(v.domain, owner._id, phone_number, CONFIRM)
Ejemplo n.º 28
0
    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)

        reminder = request.POST.get('reminder')
        phone_number = context.get('phone_number')

        if reminder and phone_number:
            phone_number = clean_phone_number(phone_number)
            v = VerifiedNumber.by_phone(phone_number, include_pending=True)
            if v and v.verified:
                user = v.owner
                if not user:
                    return self.get(request, *args, **kwargs)
                reminder_function = self.reminders.get(reminder)
                if reminder_function:
                    if reminder == 'third_soh':
                        reminder_function([user], [user.sql_location],
                                          test=True)
                    else:
                        reminder_function(user, test=True)
        messages.success(request, "Reminder was sent successfully")
        return self.get(request, *args, **kwargs)
Ejemplo n.º 29
0
 def _reassign_number(self, user, phone_number):
     v = VerifiedNumber.by_phone(phone_number, include_pending=True)
     if v.domain in self._get_logistics_domains():
         v.delete()
         user.save_verified_number(self.domain, phone_number, True)
Ejemplo n.º 30
0
def sync_ilsgateway_smsuser(domain, ilsgateway_smsuser):
    domain_part = "%s.commcarehq.org" % domain
    username_part = "%s%d" % (ilsgateway_smsuser.name.strip().replace(' ', '.').lower(), ilsgateway_smsuser.id)
    username = "******" % (username_part[:(128 - (len(domain_part) + 1))], domain_part)
    # sanity check
    assert len(username) <= 128
    user = CouchUser.get_by_username(username)
    splitted_value = ilsgateway_smsuser.name.split(' ', 1)
    first_name = last_name = ''
    if splitted_value:
        first_name = splitted_value[0][:30]
        last_name = splitted_value[1][:30] if len(splitted_value) > 1 else ''

    user_dict = {
        'first_name': first_name,
        'last_name': last_name,
        'is_active': bool(ilsgateway_smsuser.is_active),
        'email': ilsgateway_smsuser.email,
        'user_data': {}
    }

    if ilsgateway_smsuser.role:
        user_dict['user_data']['role'] = ilsgateway_smsuser.role

    if ilsgateway_smsuser.phone_numbers:
        user_dict['phone_numbers'] = [ilsgateway_smsuser.phone_numbers[0].replace('+', '')]
        user_dict['user_data']['backend'] = ilsgateway_smsuser.backend

    sp = SupplyPointCase.view('hqcase/by_domain_external_id',
                              key=[domain, str(ilsgateway_smsuser.supply_point)],
                              reduce=False,
                              include_docs=True,
                              limit=1).first()
    location_id = sp.location_id if sp else None

    if user is None and username_part:
        try:
            password = User.objects.make_random_password()
            user = CommCareUser.create(domain=domain, username=username, password=password,
                                       email=ilsgateway_smsuser.email, commit=False)
            user.first_name = first_name
            user.last_name = last_name
            user.is_active = bool(ilsgateway_smsuser.is_active)
            user.user_data = user_dict["user_data"]
            if "phone_numbers" in user_dict:
                user.set_default_phone_number(user_dict["phone_numbers"][0])
                try:
                    user.save_verified_number(domain, user_dict["phone_numbers"][0], True,
                                              ilsgateway_smsuser.backend)
                except PhoneNumberInUseException as e:
                    v = VerifiedNumber.by_phone(user_dict["phone_numbers"][0], include_pending=True)
                    v.delete()
                    user.save_verified_number(domain, user_dict["phone_numbers"][0], True,
                                              ilsgateway_smsuser.backend)
            dm = user.get_domain_membership(domain)
            dm.location_id = location_id
            user.save()
            add_location(user, location_id)

        except Exception as e:
            logging.error(e)
    else:
        dm = user.get_domain_membership(domain)
        current_location_id = dm.location_id if dm else None
        save = False

        if current_location_id != location_id:
            dm.location_id = location_id
            add_location(user, location_id)
            save = True

        if apply_updates(user, user_dict) or save:
            user.save()
    return user
Ejemplo n.º 31
0
 def _reassign_number(self, user, connection):
     v = VerifiedNumber.by_phone(connection.phone_number, include_pending=True)
     if v.domain in self._get_logistics_domains():
         v.delete()
         self.save_verified_number(user, connection)
Ejemplo n.º 32
0
 def assertNoMatch(self, phone_search, suffix_search, owner_id_search):
     self.assertIsNone(VerifiedNumber.by_phone(phone_search))
     self.assertIsNone(VerifiedNumber.by_suffix(suffix_search))
     self.assertEqual(VerifiedNumber.by_owner_id(owner_id_search), [])
Ejemplo n.º 33
0
 def verified_number(self):
     return VerifiedNumber.by_phone(self.phone_number)
Ejemplo n.º 34
0
def incoming(phone_number,
             text,
             backend_api,
             timestamp=None,
             domain_scope=None,
             delay=True):
    """
    entry point for incoming sms

    phone_number - originating phone number
    text - message content
    backend_api - backend ID of receiving sms backend
    timestamp - message received timestamp; defaults to now (UTC)
    domain_scope - if present, only messages from phone numbers that can be
      definitively linked to this domain will be processed; others will be
      dropped (useful to provide security when simulating incoming sms)
    """
    phone_number = clean_phone_number(phone_number)
    v = VerifiedNumber.by_phone(phone_number, include_pending=True)
    if domain_scope:
        # only process messages for phones known to be associated with this domain
        if v is None or v.domain != domain_scope:
            raise RuntimeError(
                'attempted to simulate incoming sms from phone number not verified with this domain'
            )

    # Log message in message log
    msg = SMSLog(phone_number=phone_number,
                 direction=INCOMING,
                 date=timestamp or datetime.utcnow(),
                 text=text,
                 backend_api=backend_api)
    if v is not None and v.verified:
        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
    msg.save()

    create_billable_for_sms(msg, backend_api, delay=delay)

    if v is not None and v.verified:
        for h in settings.SMS_HANDLERS:
            try:
                handler = to_function(h)
            except:
                logging.exception('error loading sms handler: %s' % h)
                continue

            try:
                was_handled = handler(v, text)
            except:
                logging.exception(
                    'unhandled error in sms handler %s for message [%s]' %
                    (h, text))
                was_handled = False

            if was_handled:
                break
    else:
        if not process_sms_registration(msg):
            import verify
            verify.process_verification(phone_number, text)

    return msg
Ejemplo n.º 35
0
    def validate_sms_users(self):
        for sms_user in iterate_over_api_objects(self.endpoint.get_smsusers, {'is_active': True}):
            description = ""
            user = CommCareUser.get_by_username(self.get_username(sms_user)[0])
            if not user:
                description = "Not exists"
                ILSMigrationProblem.objects.create(
                    domain=self.domain,
                    external_id=sms_user.id,
                    object_type='smsuser',
                    description=description
                )
                continue

            if user.domain != self.domain:
                description += "domain isn't correct"

            phone_numbers = {
                apply_leniency(connection.phone_number) for connection in sms_user.phone_numbers
            }

            if phone_numbers - set(user.phone_numbers):
                description += "Invalid phone numbers, "

            phone_to_backend = {
                apply_leniency(connection.phone_number): connection.backend
                for connection in sms_user.phone_numbers
            }

            default_phone_number = [
                connection.phone_number for connection in sms_user.phone_numbers if connection.default
            ]

            default_phone_number = default_phone_number[0] if default_phone_number else None

            if default_phone_number and (apply_leniency(default_phone_number) != user.default_phone_number):
                description += "Invalid default phone number, "

            for phone_number in user.phone_numbers:
                vn = VerifiedNumber.by_phone(phone_number)
                if vn and vn.owner_id != user.get_id and vn.domain == self.domain:
                    description += "Phone number already assigned to user({}) from this domain, "\
                        .format(vn.owner_id)
                elif vn and vn.domain != self.domain:
                    description += "Phone number already assigned on domain {}, ".format(vn.domain)
                elif not vn or not vn.verified:
                    description += "Phone number not verified, "
                else:
                    backend = phone_to_backend.get(phone_number)
                    if backend != 'push_backend' and vn.backend_id != 'MOBILE_BACKEND_TEST' \
                            or (backend == 'push_backend' and vn.backend_id):
                        description += "Invalid backend, "

            if description:
                migration_problem, _ = ILSMigrationProblem.objects.get_or_create(
                    domain=self.domain,
                    object_id=user.get_id,
                    object_type='smsuser'
                )
                migration_problem.external_id = sms_user.id
                migration_problem.description = description.rstrip(' ,')
                migration_problem.save()
            else:
                ILSMigrationProblem.objects.filter(
                    domain=self.domain,
                    external_id=sms_user.id,
                    object_type='smsuser'
                ).delete()
Ejemplo n.º 36
0
    def handle(self):
        text = ' '.join(self.msg.text.split()[1:])
        is_district = False
        sp = ""
        msd_code = ""

        if text.find(self.DISTRICT_REG_DELIMITER) != -1:
            phrases = [x.strip() for x in text.split(":")]
            if len(phrases) != 2:
                self.respond(REGISTER_HELP)
                return
            name = phrases[0]
            sp = phrases[1]
            role = Roles.DISTRICT_PHARMACIST
            message = REGISTRATION_CONFIRM_DISTRICT
            params = {}
            is_district = True
        else:
            names = []
            msd_codes = []
            location_regex = '^({prefs})\d+'.format(prefs='|'.join(p.lower() for p in DISTRICT_PREFIXES))
            for the_string in self.args:
                if re.match(location_regex, the_string.strip().lower()):
                    msd_codes.append(the_string.strip().lower())
                else:
                    names.append(the_string)

            name = " ".join(names)
            if len(msd_codes) != 1:
                self.respond(REGISTER_HELP)
                return
            else:
                [msd_code] = msd_codes

            role = Roles.IN_CHARGE
            message = REGISTRATION_CONFIRM
            params = {
                "msd_code": msd_code
            }

        if not self.user:
            domains = [config.domain for config in ILSGatewayConfig.get_all_configs()]
            for domain in domains:
                if is_district:
                    loc = self._get_district_location(domain, sp)
                else:
                    loc = self._get_facility_location(domain, msd_code)
                if not loc:
                    continue
                splited_name = name.split(' ', 1)
                first_name = splited_name[0]
                last_name = splited_name[1] if len(splited_name) > 1 else ""
                clean_name = name.replace(' ', '.')
                username = "******" % (clean_name, domain)
                password = User.objects.make_random_password()
                user = CommCareUser.create(domain=domain, username=username, password=password,
                                           commit=False)
                user.first_name = first_name
                user.last_name = last_name
                try:
                    user.set_default_phone_number(self.msg.phone_number.replace('+', ''))
                    user.save_verified_number(domain, self.msg.phone_number.replace('+', ''), True, self.msg.backend_api)
                except PhoneNumberInUseException as e:
                    v = VerifiedNumber.by_phone(self.msg.phone_number, include_pending=True)
                    v.delete()
                    user.save_verified_number(domain, self.msg.phone_number.replace('+', ''), True, self.msg.backend_api)
                except CommCareUser.Inconsistent:
                    continue
                user.language = Languages.DEFAULT
                params.update({
                    'sdp_name': loc.name,
                    'contact_name': name
                })

                user.user_data = {
                    'role': role
                }

                dm = user.get_domain_membership(domain)
                dm.location_id = loc._id
                user.save()
                add_location(user, loc._id)
        if params:
            self.respond(message, **params)
Ejemplo n.º 37
0
 def _reassign_number(self, user, phone_number):
     v = VerifiedNumber.by_phone(phone_number, include_pending=True)
     if v.domain in self._get_logistics_domains():
         v.delete()
         user.save_verified_number(self.domain, phone_number, True)
Ejemplo n.º 38
0
 def tearDown(self):
     self.delete_call_logs(self.domain)
     VerifiedNumber.by_phone(self.phone_number).delete()
     self.case.delete()
Ejemplo n.º 39
0
def process_incoming(msg, delay=True):
    v = VerifiedNumber.by_phone(msg.phone_number, include_pending=True)

    if v is not None and v.verified:
        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        contact = v.owner
        if isinstance(contact, CommCareUser) and hasattr(
                contact, 'location_id'):
            msg.location_id = contact.location_id
        msg.save()

    if msg.domain_scope:
        # only process messages for phones known to be associated with this domain
        if v is None or v.domain != msg.domain_scope:
            raise DomainScopeValidationError(
                'Attempted to simulate incoming sms from phone number not ' \
                'verified with this domain'
            )

    can_receive_sms = PhoneNumber.can_receive_sms(msg.phone_number)
    opt_in_keywords, opt_out_keywords = get_opt_keywords(msg)
    if is_opt_message(msg.text, opt_out_keywords) and can_receive_sms:
        if PhoneNumber.opt_out_sms(msg.phone_number):
            metadata = MessageMetadata(ignore_opt_out=True)
            text = get_message(MSG_OPTED_OUT,
                               v,
                               context=(opt_in_keywords[0], ))
            if v:
                send_sms_to_verified_number(v, text, metadata=metadata)
            else:
                send_sms(msg.domain,
                         None,
                         msg.phone_number,
                         text,
                         metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords) and not can_receive_sms:
        if PhoneNumber.opt_in_sms(msg.phone_number):
            text = get_message(MSG_OPTED_IN,
                               v,
                               context=(opt_out_keywords[0], ))
            if v:
                send_sms_to_verified_number(v, text)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    elif v is not None and v.verified:
        if domain_has_privilege(msg.domain, privileges.INBOUND_SMS):
            for h in settings.SMS_HANDLERS:
                try:
                    handler = to_function(h)
                except:
                    notify_exception(None,
                                     message=('error loading sms handler: %s' %
                                              h))
                    continue

                try:
                    was_handled = handler(v, msg.text, msg=msg)
                except Exception, e:
                    log_sms_exception(msg)
                    was_handled = False

                if was_handled:
                    break
Ejemplo n.º 40
0
    def sms_user_sync(self, ilsgateway_smsuser, username_part=None, password=None,
                      first_name='', last_name=''):
        domain_part = "%s.commcarehq.org" % self.domain
        if not username_part:
            username_part = "%s%d" % (ilsgateway_smsuser.name.strip().replace(' ', '.').lower(),
                                      ilsgateway_smsuser.id)
        username = "******" % (username_part[:(128 - (len(domain_part) + 1))], domain_part)
        # sanity check
        assert len(username) <= 128
        user = CouchUser.get_by_username(username)
        splitted_value = ilsgateway_smsuser.name.split(' ', 1)
        if not first_name:
            first_name = splitted_value[0][:30] if splitted_value else ''

        if not last_name:
            last_name = splitted_value[1][:30] if len(splitted_value) > 1 else ''

        language = ilsgateway_smsuser.language

        user_dict = {
            'first_name': first_name,
            'last_name': last_name,
            'is_active': bool(ilsgateway_smsuser.is_active),
            'email': ilsgateway_smsuser.email,
            'user_data': {}
        }

        if ilsgateway_smsuser.role:
            user_dict['user_data']['role'] = ilsgateway_smsuser.role

        if ilsgateway_smsuser.phone_numbers:
            user_dict['phone_numbers'] = [ilsgateway_smsuser.phone_numbers[0].replace('+', '')]
            user_dict['user_data']['backend'] = ilsgateway_smsuser.backend

        if user is None and username_part:
            try:
                user_password = password or User.objects.make_random_password()
                user = CommCareUser.create(domain=self.domain, username=username, password=user_password,
                                           email=ilsgateway_smsuser.email, commit=False,
                                           password_hashed=bool(password))
                user.first_name = first_name
                user.last_name = last_name
                user.language = language
                user.is_active = bool(ilsgateway_smsuser.is_active)
                user.user_data = user_dict["user_data"]
                if "phone_numbers" in user_dict:
                    user.set_default_phone_number(user_dict["phone_numbers"][0])
                    try:
                        user.save_verified_number(self.domain, user_dict["phone_numbers"][0], True,
                                                  ilsgateway_smsuser.backend)
                    except PhoneNumberInUseException as e:
                        v = VerifiedNumber.by_phone(user_dict["phone_numbers"][0], include_pending=True)
                        v.delete()
                        user.save_verified_number(self.domain, user_dict["phone_numbers"][0], True,
                                                  ilsgateway_smsuser.backend)
            except Exception as e:
                logging.error(e)
        else:
            if apply_updates(user, user_dict):
                user.save()
        return user
Ejemplo n.º 41
0
 def get_context_data(self, **kwargs):
     context = super(BaseRemindersTester, self).get_context_data(**kwargs)
     context['phone_number'] = kwargs.get('phone_number')
     verified_number = VerifiedNumber.by_phone(context['phone_number'])
     context['phone_user'] = CommCareUser.get(verified_number.owner_id) if verified_number else None
     return context
Ejemplo n.º 42
0
    def handle(self):
        text = ' '.join(self.msg.text.split()[1:])
        is_district = False
        sp = ""
        msd_code = ""

        if text.find(self.DISTRICT_REG_DELIMITER) != -1:
            phrases = [x.strip() for x in text.split(":")]
            if len(phrases) != 2:
                self.respond(REGISTER_HELP)
                return
            name = phrases[0]
            sp = phrases[1]
            role = Roles.DISTRICT_PHARMACIST
            message = REGISTRATION_CONFIRM_DISTRICT
            params = {}
            is_district = True
        else:
            names = []
            msd_codes = []
            location_regex = '^({prefs})\d+'.format(prefs='|'.join(
                p.lower() for p in DISTRICT_PREFIXES))
            for the_string in self.args:
                if re.match(location_regex, the_string.strip().lower()):
                    msd_codes.append(the_string.strip().lower())
                else:
                    names.append(the_string)

            name = " ".join(names)
            if len(msd_codes) != 1:
                self.respond(REGISTER_HELP)
                return
            else:
                [msd_code] = msd_codes

            role = Roles.IN_CHARGE
            message = REGISTRATION_CONFIRM
            params = {"msd_code": msd_code}

        if not self.user:
            domains = [
                config.domain for config in ILSGatewayConfig.get_all_configs()
            ]
            for domain in domains:
                if is_district:
                    loc = self._get_district_location(domain, sp)
                else:
                    loc = self._get_facility_location(domain, msd_code)
                if not loc:
                    continue
                splited_name = name.split(' ', 1)
                first_name = splited_name[0]
                last_name = splited_name[1] if len(splited_name) > 1 else ""
                clean_name = name.replace(' ', '.')
                username = "******" % (clean_name, domain)
                password = User.objects.make_random_password()
                user = CommCareUser.create(domain=domain,
                                           username=username,
                                           password=password,
                                           commit=False)
                user.first_name = first_name
                user.last_name = last_name
                try:
                    user.set_default_phone_number(
                        self.msg.phone_number.replace('+', ''))
                    user.save_verified_number(
                        domain, self.msg.phone_number.replace('+', ''), True,
                        self.msg.backend_api)
                except PhoneNumberInUseException as e:
                    v = VerifiedNumber.by_phone(self.msg.phone_number,
                                                include_pending=True)
                    v.delete()
                    user.save_verified_number(
                        domain, self.msg.phone_number.replace('+', ''), True,
                        self.msg.backend_api)
                except CommCareUser.Inconsistent:
                    continue
                user.language = Languages.DEFAULT
                params.update({'sdp_name': loc.name, 'contact_name': name})

                user.user_data = {'role': role}

                dm = user.get_domain_membership(domain)
                dm.location_id = loc._id
                user.save()
                add_location(user, loc._id)
        if params:
            self.respond(message, **params)
Ejemplo n.º 43
0
def sync_ilsgateway_smsuser(domain, ilsgateway_smsuser):
    domain_part = "%s.commcarehq.org" % domain
    username_part = "%s%d" % (ilsgateway_smsuser.name.strip().replace(' ', '.').lower(), ilsgateway_smsuser.id)
    username = "******" % (username_part[:(128 - len(domain_part))], domain_part)
    #sanity check
    assert len(username) <= 128
    user = CouchUser.get_by_username(username)
    splitted_value = ilsgateway_smsuser.name.split(' ', 1)
    first_name = last_name = ''
    if splitted_value:
        first_name = splitted_value[0][:30]
        last_name = splitted_value[1][:30] if len(splitted_value) > 1 else ''

    user_dict = {
        'first_name': first_name,
        'last_name': last_name,
        'is_active': bool(ilsgateway_smsuser.is_active),
        'email': ilsgateway_smsuser.email,
        'user_data': {}
    }

    if ilsgateway_smsuser.role:
        user_dict['user_data']['role'] = ilsgateway_smsuser.role

    if ilsgateway_smsuser.phone_numbers:
        user_dict['phone_numbers'] = [ilsgateway_smsuser.phone_numbers[0].replace('+', '')]
        user_dict['user_data']['backend'] = ilsgateway_smsuser.backend

    sp = SupplyPointCase.view('hqcase/by_domain_external_id',
                              key=[domain, str(ilsgateway_smsuser.supply_point)],
                              reduce=False,
                              include_docs=True,
                              limit=1).first()
    location_id = sp.location_id if sp else None

    if user is None and username_part:
        try:
            password = User.objects.make_random_password()
            user = CommCareUser.create(domain=domain, username=username, password=password,
                                       email=ilsgateway_smsuser.email, commit=False)
            user.first_name = first_name
            user.last_name = last_name
            user.is_active = bool(ilsgateway_smsuser.is_active)
            user.user_data = user_dict["user_data"]
            if "phone_numbers" in user_dict:
                user.set_default_phone_number(user_dict["phone_numbers"][0])
                try:
                    user.save_verified_number(domain, user_dict["phone_numbers"][0], True, ilsgateway_smsuser.backend)
                except PhoneNumberInUseException as e:
                    v = VerifiedNumber.by_phone(user_dict["phone_numbers"][0], include_pending=True)
                    v.delete()
                    user.save_verified_number(domain, user_dict["phone_numbers"][0], True, ilsgateway_smsuser.backend)
            dm = user.get_domain_membership(domain)
            dm.location_id = location_id
            user.save()
            add_location(user, location_id)

        except Exception as e:
            logging.error(e)
    else:
        dm = user.get_domain_membership(domain)
        current_location_id = dm.location_id if dm else None
        save = False

        if current_location_id != location_id:
            dm.location_id = location_id
            add_location(user, location_id)
            save = True

        if apply_updates(user, user_dict) or save:
            user.save()
    return user