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)
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
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
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()
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
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
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))
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
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
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))
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
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)
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
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
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)
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()
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()
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)
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()
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()
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)
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)
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')
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
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)
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)
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)
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)
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
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)
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), [])
def verified_number(self): return VerifiedNumber.by_phone(self.phone_number)
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
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()
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)
def tearDown(self): self.delete_call_logs(self.domain) VerifiedNumber.by_phone(self.phone_number).delete() self.case.delete()
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
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
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
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)
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