def test_any_migrations_in_progress(self):
     self.assertFalse(any_migrations_in_progress('purple'))
     set_migration_started('purple', self.slug)
     self.assertTrue(any_migrations_in_progress('purple'))
     set_migration_started('purple', 'other_slug')
     set_migration_not_started('purple', self.slug)
     self.assertTrue(any_migrations_in_progress('purple'))
     set_migration_complete('purple', 'other_slug')
     self.assertFalse(any_migrations_in_progress('purple'))
Пример #2
0
def check_data_migration_in_progress(domain, last_migration_check_time):
    utcnow = datetime.utcnow()
    if last_migration_check_time is None or (
            utcnow - last_migration_check_time) > timedelta(minutes=1):
        return any_migrations_in_progress(domain), utcnow

    return False, last_migration_check_time
Пример #3
0
    def _handle_basic_failure_modes(self):
        if any_migrations_in_progress(self.domain):
            # keep submissions on the phone
            # until ready to start accepting again
            return HttpResponse(status=503)

        if not self.auth_context.is_valid():
            return HttpResponseForbidden('Bad auth')
Пример #4
0
def run_case_update_rules(now=None):
    domains = (AutomaticUpdateRule.objects.filter(
        active=True,
        deleted=False,
        workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE).values_list(
            'domain', flat=True).distinct().order_by('domain'))
    for domain in domains:
        if not any_migrations_in_progress(domain):
            run_case_update_rules_for_domain.delay(domain, now)
Пример #5
0
def run_case_update_rules(now=None):
    domains = (AutomaticUpdateRule
               .objects
               .filter(active=True, deleted=False, workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE)
               .values_list('domain', flat=True)
               .distinct()
               .order_by('domain'))
    for domain in domains:
        if not any_migrations_in_progress(domain):
            run_case_update_rules_for_domain.delay(domain, now)
Пример #6
0
    def _handle_basic_failure_modes(self):
        if any_migrations_in_progress(self.domain):
            # keep submissions on the phone
            # until ready to start accepting again
            return HttpResponse(status=503)

        if not self.auth_context.is_valid():
            return HttpResponseForbidden('Bad auth')

        if isinstance(self.instance, BadRequest):
            return HttpResponseBadRequest(self.instance.message)
Пример #7
0
    def _handle_basic_failure_modes(self):
        if any_migrations_in_progress(self.domain):
            # keep submissions on the phone
            # until ready to start accepting again
            return HttpResponse(status=503), None, []

        if not self.auth_context.is_valid():
            return self.failed_auth_response, None, []

        if isinstance(self.instance, BadRequest):
            return HttpResponseBadRequest(self.instance.message), None, []
Пример #8
0
def reprocess_unfinished_stub(stub, save=True):
    if any_migrations_in_progress(stub.domain):
        logger.info("Ignoring stub during data migration: %s", stub.xform_id)
        return

    form_id = stub.xform_id
    try:
        form = FormAccessors(stub.domain).get_form(form_id)
    except XFormNotFound:
        # form doesn't exist which means the failure probably happend during saving so
        # let mobile handle re-submitting it
        logger.error('Form not found: %s', form_id)
        save and stub.delete()
        return

    return reprocess_unfinished_stub_with_form(stub, form, save)
Пример #9
0
def process_pre_registration(msg):
    """
    Returns True if this message was part of the SMS pre-registration
    workflow (see corehq.apps.sms.models.SelfRegistrationInvitation).
    Returns False if it's not part of the pre-registration workflow or
    if the workflow has already been completed.
    """
    invitation = SelfRegistrationInvitation.by_phone(msg.phone_number)
    if not invitation:
        return False

    if any_migrations_in_progress(invitation.domain):
        raise DelayProcessing()

    domain_obj = Domain.get_by_name(invitation.domain, strict=True)
    if not domain_obj.sms_mobile_worker_registration_enabled:
        return False

    text = msg.text.strip()
    if is_registration_text(text):
        # Return False to let the message be processed through the SMS
        # registration workflow
        return False
    elif invitation.phone_type:
        # If the user has already indicated what kind of phone they have,
        # but is still replying with sms, then just resend them the
        # appropriate registration instructions
        if invitation.phone_type == SelfRegistrationInvitation.PHONE_TYPE_ANDROID:
            invitation.send_step2_android_sms()
        elif invitation.phone_type == SelfRegistrationInvitation.PHONE_TYPE_OTHER:
            invitation.send_step2_java_sms()
        return True
    elif text == '1':
        invitation.phone_type = SelfRegistrationInvitation.PHONE_TYPE_ANDROID
        invitation.save()
        invitation.send_step2_android_sms()
        return True
    elif text == '2':
        invitation.phone_type = SelfRegistrationInvitation.PHONE_TYPE_OTHER
        invitation.save()
        invitation.send_step2_java_sms()
        return True
    else:
        invitation.send_step1_sms()
        return True
Пример #10
0
def process_pre_registration(msg):
    """
    Returns True if this message was part of the SMS pre-registration
    workflow (see corehq.apps.sms.models.SelfRegistrationInvitation).
    Returns False if it's not part of the pre-registration workflow or
    if the workflow has already been completed.
    """
    invitation = SelfRegistrationInvitation.by_phone(msg.phone_number)
    if not invitation:
        return False

    if any_migrations_in_progress(invitation.domain):
        raise DelayProcessing()

    domain_obj = Domain.get_by_name(invitation.domain, strict=True)
    if not domain_obj.sms_mobile_worker_registration_enabled:
        return False

    text = msg.text.strip()
    if is_registration_text(text):
        # Return False to let the message be processed through the SMS
        # registration workflow
        return False
    elif invitation.phone_type:
        # If the user has already indicated what kind of phone they have,
        # but is still replying with sms, then just resend them the
        # appropriate registration instructions
        if invitation.phone_type == SelfRegistrationInvitation.PHONE_TYPE_ANDROID:
            invitation.send_step2_android_sms()
        elif invitation.phone_type == SelfRegistrationInvitation.PHONE_TYPE_OTHER:
            invitation.send_step2_java_sms()
        return True
    elif text == '1':
        invitation.phone_type = SelfRegistrationInvitation.PHONE_TYPE_ANDROID
        invitation.save()
        invitation.send_step2_android_sms()
        return True
    elif text == '2':
        invitation.phone_type = SelfRegistrationInvitation.PHONE_TYPE_OTHER
        invitation.save()
        invitation.send_step2_java_sms()
        return True
    else:
        invitation.send_step1_sms()
        return True
Пример #11
0
def reprocess_unfinished_stub(stub, save=True):
    if any_migrations_in_progress(stub.domain):
        logger.info("Ignoring stub during data migration: %s", stub.xform_id)
        return

    form_id = stub.xform_id
    try:
        form = FormAccessors(stub.domain).get_form(form_id)
    except XFormNotFound:
        if stub.saved:
            logger.error("Form not found for reprocessing", extra={
                'form_id': form_id,
                'domain': stub.domain
            })
        save and stub.delete()
        return

    return reprocess_unfinished_stub_with_form(stub, form, save)
Пример #12
0
def run_case_update_rules(now=None):
    domains = (AutomaticUpdateRule.objects.filter(
        active=True,
        deleted=False,
        workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE).values_list(
            'domain', flat=True).distinct().order_by('domain'))
    hour_to_run = now.hour if now else datetime.utcnow().hour
    for domain in domains:
        if not any_migrations_in_progress(
                domain
        ) and not DISABLE_CASE_UPDATE_RULE_SCHEDULED_TASK.enabled(domain):
            domain_obj = Domain.get_by_name(domain)
            if domain_obj.auto_case_update_hour is None:
                domain_hour = settings.RULE_UPDATE_HOUR
            else:
                domain_hour = domain_obj.auto_case_update_hour
            if hour_to_run == domain_hour:
                run_case_update_rules_for_domain.delay(domain, now)
def skip_domain(domain):
    return (
        any_migrations_in_progress(domain) or
        REMINDERS_MIGRATION_IN_PROGRESS.enabled(domain)
    )
Пример #14
0
def skip_domain(domain):
    return any_migrations_in_progress(domain)
Пример #15
0
def skip_domain(domain):
    return (any_migrations_in_progress(domain)
            or REMINDERS_MIGRATION_IN_PROGRESS.enabled(domain))
Пример #16
0
def skip_domain(domain):
    return any_migrations_in_progress(domain)
Пример #17
0
def check_data_migration_in_progress(domain, last_migration_check_time):
    utcnow = datetime.utcnow()
    if last_migration_check_time is None or (utcnow - last_migration_check_time) > timedelta(minutes=1):
        return any_migrations_in_progress(domain), utcnow

    return False, last_migration_check_time
Пример #18
0
def process_sms_registration(msg):
    """
    This method handles registration via sms.
    Returns True if a contact was registered, False if not.

    To have a case register itself, do the following:

        1) Select "Enable Case Registration Via SMS" in project settings, and fill in the
        associated Case Registration settings.

        2) Text in "join <domain>", where <domain> is the domain to join. If the sending
        number does not exist in the system, a case will be registered tied to that number.
        The "join" keyword can be any keyword in REGISTRATION_KEYWORDS. This is meant to
        support multiple translations.

    To have a mobile worker register itself, do the following:

        1) Select "Enable Mobile Worker Registration via SMS" in project settings.

        2) Text in "join <domain> worker <username>", where <domain> is the domain to join and <username> is the
        requested username.  If the username doesn't exist it will be created, otherwise the registration will error.
        If the username argument is not specified, the username will be the mobile number

        The "join" and "worker" keywords can be any keyword in REGISTRATION_KEYWORDS and
        REGISTRATION_MOBILE_WORKER_KEYWORDS, respectively. This is meant to support multiple
        translations.
    """
    registration_processed = False
    text_words = msg.text.upper().split()
    keyword1 = text_words[0] if len(text_words) > 0 else ""
    keyword2 = text_words[1].lower() if len(text_words) > 1 else ""
    keyword3 = text_words[2] if len(text_words) > 2 else ""
    keyword4 = text_words[3] if len(text_words) > 3 else ""
    cleaned_phone_number = strip_plus(msg.phone_number)
    if is_registration_text(msg.text) and keyword2 != "":
        domain_name = keyword2

        if any_migrations_in_progress(domain_name):
            raise DelayProcessing()

        domain_obj = Domain.get_by_name(domain_name, strict=True)

        if domain_obj is not None:
            if domain_has_privilege(domain_obj, privileges.INBOUND_SMS):
                if (keyword3 in REGISTRATION_MOBILE_WORKER_KEYWORDS
                        and domain_obj.sms_mobile_worker_registration_enabled):
                    if keyword4 != '':
                        username = keyword4
                    else:
                        username = cleaned_phone_number
                    try:
                        user_data = {}

                        invitation = SelfRegistrationInvitation.by_phone(
                            msg.phone_number)
                        if invitation:
                            invitation.completed()
                            user_data = invitation.custom_user_data

                        username = process_username(username, domain_obj)
                        password = random_password()
                        new_user = CommCareUser.create(domain_obj.name,
                                                       username,
                                                       password,
                                                       user_data=user_data)
                        new_user.add_phone_number(cleaned_phone_number)
                        new_user.save()

                        entry = new_user.get_or_create_phone_entry(
                            cleaned_phone_number)
                        entry.set_two_way()
                        entry.set_verified()
                        entry.save()
                        registration_processed = True

                        if domain_obj.enable_registration_welcome_sms_for_mobile_worker:
                            send_sms(
                                domain_obj.name, None, cleaned_phone_number,
                                get_message(
                                    MSG_REGISTRATION_WELCOME_MOBILE_WORKER,
                                    domain=domain_obj.name))
                    except ValidationError as e:
                        send_sms(domain_obj.name, None, cleaned_phone_number,
                                 e.messages[0])

                elif domain_obj.sms_case_registration_enabled:
                    register_sms_contact(
                        domain=domain_obj.name,
                        case_type=domain_obj.sms_case_registration_type,
                        case_name="unknown",
                        user_id=domain_obj.sms_case_registration_user_id,
                        contact_phone_number=cleaned_phone_number,
                        contact_phone_number_is_verified="1",
                        owner_id=domain_obj.sms_case_registration_owner_id,
                    )
                    registration_processed = True
                    if domain_obj.enable_registration_welcome_sms_for_case:
                        send_sms(
                            domain_obj.name, None, cleaned_phone_number,
                            get_message(MSG_REGISTRATION_WELCOME_CASE,
                                        domain=domain_obj.name))
            msg.domain = domain_obj.name
            msg.save()

    return registration_processed
Пример #19
0
def process_incoming(msg):
    v, has_domain_two_way_scope = get_inbound_phone_entry(msg)

    if v:
        if any_migrations_in_progress(v.domain):
            raise DelayProcessing()

        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        msg.location_id = get_location_id_by_verified_number(v)
        msg.save()
    elif msg.domain_scope:
        if any_migrations_in_progress(msg.domain_scope):
            raise DelayProcessing()

        msg.domain = msg.domain_scope
        msg.save()

    opt_in_keywords, opt_out_keywords, pass_through_opt_in_keywords = get_opt_keywords(msg)
    domain = v.domain if v else None

    if is_opt_message(msg.text, opt_out_keywords):
        if PhoneBlacklist.opt_out_sms(msg.phone_number, domain=domain):
            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)
            elif msg.backend_id:
                send_sms_with_backend(msg.domain, msg.phone_number, text, msg.backend_id, metadata=metadata)
            else:
                send_sms(msg.domain, None, msg.phone_number, text, metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords):
        if PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain):
            text = get_message(MSG_OPTED_IN, v, context=(opt_out_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text)
            elif msg.backend_id:
                send_sms_with_backend(msg.domain, msg.phone_number, text, msg.backend_id)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    else:
        if is_opt_message(msg.text, pass_through_opt_in_keywords):
            # Opt the phone number in, and then process the message normally
            PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain)

        handled = False
        is_two_way = v is not None and v.is_two_way

        if msg.domain and domain_has_privilege(msg.domain, privileges.INBOUND_SMS):
            handled = load_and_call(settings.CUSTOM_SMS_HANDLERS, v, msg.text, msg)

            if not handled and v and v.pending_verification:
                from . import verify
                handled = verify.process_verification(v, msg,
                    create_subevent_for_inbound=not has_domain_two_way_scope)

            if (
                not handled
                and (is_two_way or has_domain_two_way_scope)
                and is_contact_active(v.domain, v.owner_doc_type, v.owner_id)
            ):
                handled = load_and_call(settings.SMS_HANDLERS, v, msg.text, msg)

        if not handled and not is_two_way:
            handled = process_pre_registration(msg)

            if not handled:
                handled = process_sms_registration(msg)

    # If the sms queue is enabled, then the billable gets created in remove_from_queue()
    if (
        not settings.SMS_QUEUE_ENABLED and
        msg.domain and
        domain_has_privilege(msg.domain, privileges.INBOUND_SMS)
    ):
        create_billable_for_sms(msg)
Пример #20
0
def process_sms_registration(msg):
    """
    This method handles registration via sms.
    Returns True if a contact was registered, False if not.

    To have a case register itself, do the following:

        1) Select "Enable Case Registration Via SMS" in project settings, and fill in the
        associated Case Registration settings.

        2) Text in "join <domain>", where <domain> is the domain to join. If the sending
        number does not exist in the system, a case will be registered tied to that number.
        The "join" keyword can be any keyword in REGISTRATION_KEYWORDS. This is meant to
        support multiple translations.

    To have a mobile worker register itself, do the following:

        1) Select "Enable Mobile Worker Registration via SMS" in project settings.

        2) Text in "join <domain> worker <username>", where <domain> is the domain to join and <username> is the
        requested username.  If the username doesn't exist it will be created, otherwise the registration will error.
        If the username argument is not specified, the username will be the mobile number

        The "join" and "worker" keywords can be any keyword in REGISTRATION_KEYWORDS and
        REGISTRATION_MOBILE_WORKER_KEYWORDS, respectively. This is meant to support multiple
        translations.
    """
    registration_processed = False
    text_words = msg.text.upper().split()
    keyword1 = text_words[0] if len(text_words) > 0 else ""
    keyword2 = text_words[1].lower() if len(text_words) > 1 else ""
    keyword3 = text_words[2] if len(text_words) > 2 else ""
    keyword4 = text_words[3] if len(text_words) > 3 else ""
    cleaned_phone_number = strip_plus(msg.phone_number)
    if is_registration_text(msg.text) and keyword2 != "":
        domain_name = keyword2

        if any_migrations_in_progress(domain_name):
            raise DelayProcessing()

        domain_obj = Domain.get_by_name(domain_name, strict=True)

        if domain_obj is not None:
            if domain_has_privilege(domain_obj, privileges.INBOUND_SMS):
                if (
                        keyword3 in REGISTRATION_MOBILE_WORKER_KEYWORDS
                        and domain_obj.sms_mobile_worker_registration_enabled
                ):
                    if keyword4 != '':
                        username = keyword4
                    else:
                        username = cleaned_phone_number
                    try:
                        user_data = {}

                        invitation = SelfRegistrationInvitation.by_phone(msg.phone_number)
                        if invitation:
                            invitation.completed()
                            user_data = invitation.custom_user_data

                        username = process_username(username, domain_obj)
                        password = random_password()
                        new_user = CommCareUser.create(domain_obj.name, username, password, user_data=user_data)
                        new_user.add_phone_number(cleaned_phone_number)
                        new_user.save()

                        entry = new_user.get_or_create_phone_entry(cleaned_phone_number)
                        entry.set_two_way()
                        entry.set_verified()
                        entry.save()
                        registration_processed = True

                        if domain_obj.enable_registration_welcome_sms_for_mobile_worker:
                            send_sms(domain_obj.name, None, cleaned_phone_number,
                                     get_message(MSG_REGISTRATION_WELCOME_MOBILE_WORKER, domain=domain_obj.name))
                    except ValidationError as e:
                        send_sms(domain_obj.name, None, cleaned_phone_number, e.messages[0])

                elif domain_obj.sms_case_registration_enabled:
                    register_sms_contact(
                        domain=domain_obj.name,
                        case_type=domain_obj.sms_case_registration_type,
                        case_name="unknown",
                        user_id=domain_obj.sms_case_registration_user_id,
                        contact_phone_number=cleaned_phone_number,
                        contact_phone_number_is_verified="1",
                        owner_id=domain_obj.sms_case_registration_owner_id,
                    )
                    registration_processed = True
                    if domain_obj.enable_registration_welcome_sms_for_case:
                        send_sms(domain_obj.name, None, cleaned_phone_number,
                                 get_message(MSG_REGISTRATION_WELCOME_CASE, domain=domain_obj.name))
            msg.domain = domain_obj.name
            msg.save()

    return registration_processed
Пример #21
0
def process_incoming(msg):
    sms_load_counter("inbound", msg.domain)()
    v, has_domain_two_way_scope = get_inbound_phone_entry(msg)

    if v:
        if any_migrations_in_progress(v.domain):
            raise DelayProcessing()

        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        msg.location_id = get_location_id_by_verified_number(v)
        msg.save()
    elif msg.domain_scope:
        if any_migrations_in_progress(msg.domain_scope):
            raise DelayProcessing()

        msg.domain = msg.domain_scope
        msg.save()

    opt_in_keywords, opt_out_keywords, pass_through_opt_in_keywords = get_opt_keywords(
        msg)
    domain = v.domain if v else None

    if is_opt_message(msg.text, opt_out_keywords):
        if PhoneBlacklist.opt_out_sms(msg.phone_number, domain=domain):
            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)
            elif msg.backend_id:
                send_sms_with_backend(msg.domain,
                                      msg.phone_number,
                                      text,
                                      msg.backend_id,
                                      metadata=metadata)
            else:
                send_sms(msg.domain,
                         None,
                         msg.phone_number,
                         text,
                         metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords):
        if PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain):
            text = get_message(MSG_OPTED_IN,
                               v,
                               context=(opt_out_keywords[0], ))
            if v:
                send_sms_to_verified_number(v, text)
            elif msg.backend_id:
                send_sms_with_backend(msg.domain, msg.phone_number, text,
                                      msg.backend_id)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    else:
        if is_opt_message(msg.text, pass_through_opt_in_keywords):
            # Opt the phone number in, and then process the message normally
            PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain)

        handled = False
        is_two_way = v is not None and v.is_two_way

        if msg.domain and domain_has_privilege(msg.domain,
                                               privileges.INBOUND_SMS):
            if v and v.pending_verification:
                from . import verify
                handled = verify.process_verification(
                    v,
                    msg,
                    create_subevent_for_inbound=not has_domain_two_way_scope)

            if ((is_two_way or has_domain_two_way_scope) and is_contact_active(
                    v.domain, v.owner_doc_type, v.owner_id)):
                handled = load_and_call(settings.SMS_HANDLERS, v, msg.text,
                                        msg)

        if not handled and not is_two_way:
            handled = process_pre_registration(msg)

            if not handled:
                handled = process_sms_registration(msg)

    # If the sms queue is enabled, then the billable gets created in remove_from_queue()
    if (not settings.SMS_QUEUE_ENABLED and msg.domain
            and domain_has_privilege(msg.domain, privileges.INBOUND_SMS)):
        create_billable_for_sms(msg)
Пример #22
0
def skip_domain(domain):
    return DATA_MIGRATION.enabled(domain) or any_migrations_in_progress(domain)