def test_update_form_references_form_link(self):
        app = Application.new_app('domain', 'Foo')
        app.modules.append(Module(forms=[Form()]))
        app.modules.append(Module(forms=[Form(), Form()]))
        app.build_spec = BuildSpec.from_string('2.7.0/latest')
        app.get_module(0).get_form(0).source = get_simple_form(
            xmlns='xmlns-0.0')
        app.get_module(1).get_form(0).source = get_simple_form(xmlns='xmlns-1')

        original_form_id1 = app.get_module(1).get_form(0).unique_id
        original_form_id2 = app.get_module(1).get_form(1).unique_id
        app.get_module(0).get_form(0).form_links = [
            FormLink(xpath="", form_id=original_form_id1),
            FormLink(xpath="", form_id=original_form_id2),
        ]

        copy = Application.from_source(app.export_json(dump_json=False),
                                       'domain')
        new_form_id1 = copy.get_module(1).get_form(0).unique_id
        new_form_id2 = copy.get_module(1).get_form(1).unique_id
        self.assertNotEqual(original_form_id1, new_form_id1)
        self.assertNotEqual(original_form_id2, new_form_id2)
        self.assertEqual(new_form_id1,
                         copy.get_module(0).get_form(0).form_links[0].form_id)
        self.assertEqual(new_form_id2,
                         copy.get_module(0).get_form(0).form_links[1].form_id)
Example #2
0
    def dehydrate_module(self, app, module, langs):
        """
        Convert a Module object to a JValue representation
        with just the good parts.

        NOTE: This is not a tastypie "magic"-name method to
        dehydrate the "module" field; there is no such field.
        """
        dehydrated = {}

        dehydrated['case_type'] = module.case_type

        dehydrated['case_properties'] = app_manager_util.get_case_properties(app, [module.case_type], defaults=['name'])[module.case_type]

        dehydrated['forms'] = []
        for form in module.forms:
            form = Form.get_form(form.unique_id)
            form_jvalue = {
                'xmlns': form.xmlns,
                'name': form.name,
                'questions': form.get_questions(langs),
            }
            dehydrated['forms'].append(form_jvalue)

        return dehydrated
Example #3
0
def keyword_uses_form_that_requires_case(survey_keyword):
    for action in survey_keyword.actions:
        if action.action in [METHOD_SMS_SURVEY, METHOD_STRUCTURED_SMS]:
            form = Form.get_form(action.form_unique_id)
            if form.requires_case():
                return True
    return False
Example #4
0
def get_form_name(form_unique_id):
    try:
        form = Form.get_form(form_unique_id)
    except ResourceNotFound:
        return _("[unknown]")

    return form.full_path_name
Example #5
0
def start_session_from_keyword(survey_keyword, verified_number):
    try:
        form_unique_id = survey_keyword.form_unique_id
        form = Form.get_form(form_unique_id)
        app = form.get_app()
        module = form.get_module()

        if verified_number.owner_doc_type == "CommCareCase":
            case_id = verified_number.owner_id
        else:
            #TODO: Need a way to choose the case when it's a user that's playing the form
            case_id = None

        session, responses = start_session(verified_number.domain,
                                           verified_number.owner, app, module,
                                           form, case_id)

        if len(responses) > 0:
            message = format_message_list(responses)
            send_sms_to_verified_number(verified_number, message)

    except Exception:
        logging.exception(
            "Exception while starting survey for keyword %s, domain %s" %
            (survey_keyword.keyword, verified_number.domain))
Example #6
0
def keyword_uses_form_that_requires_case(survey_keyword):
    for action in survey_keyword.keywordaction_set.all():
        if action.action in [KeywordAction.ACTION_SMS_SURVEY, KeywordAction.ACTION_STRUCTURED_SMS]:
            form = Form.get_form(action.form_unique_id)
            if form.requires_case():
                return True
    return False
Example #7
0
def keyword_uses_form_that_requires_case(survey_keyword):
    for action in survey_keyword.keywordaction_set.all():
        if action.action in [KeywordAction.ACTION_SMS_SURVEY, KeywordAction.ACTION_STRUCTURED_SMS]:
            form = Form.get_form(action.form_unique_id)
            if form.requires_case():
                return True
    return False
Example #8
0
def create_data_source_from_app(request, domain):
    if request.method == 'POST':
        form = ConfigurableDataSourceFromAppForm(domain, request.POST)
        if form.is_valid():
            # save config
            app_source = form.app_source_helper.get_app_source(form.cleaned_data)
            app = Application.get(app_source.application)
            if app_source.source_type == 'case':
                data_source = get_case_data_source(app, app_source.source)
                data_source.save()
                messages.success(request, _(u"Data source created for '{}'".format(app_source.source)))
            else:
                assert app_source.source_type == 'form'
                xform = Form.get_form(app_source.source)
                data_source = get_form_data_source(app, xform)
                data_source.save()
                messages.success(request, _(u"Data source created for '{}'".format(xform.default_name())))

            return HttpResponseRedirect(reverse('edit_configurable_data_source', args=[domain, data_source._id]))
    else:
        form = ConfigurableDataSourceFromAppForm(domain)
    context = _shared_context(domain)
    context['sources_map'] = form.app_source_helper.all_sources
    context['form'] = form
    return render(request, 'userreports/data_source_from_app.html', context)
Example #9
0
    def dehydrate_module(self, app, module, langs):
        """
        Convert a Module object to a JValue representation
        with just the good parts.

        NOTE: This is not a tastypie "magic"-name method to
        dehydrate the "module" field; there is no such field.
        """
        dehydrated = {}

        dehydrated['case_type'] = module.case_type

        dehydrated['case_properties'] = app_manager_util.get_case_properties(
            app, [module.case_type], defaults=['name'])[module.case_type]

        dehydrated['forms'] = []
        for form in module.forms:
            form = Form.get_form(form.unique_id)
            form_jvalue = {
                'xmlns': form.xmlns,
                'name': form.name,
                'questions': form.get_questions(langs),
            }
            dehydrated['forms'].append(form_jvalue)

        return dehydrated
Example #10
0
    def dehydrate_module(self, app, module, langs):
        """
        Convert a Module object to a JValue representation
        with just the good parts.

        NOTE: This is not a tastypie "magic"-name method to
        dehydrate the "module" field; there is no such field.
        """
        try:
            dehydrated = {}

            dehydrated["case_type"] = module.case_type

            dehydrated["case_properties"] = app_manager_util.get_case_properties(
                app, [module.case_type], defaults=["name"]
            )[module.case_type]

            dehydrated["unique_id"] = module.unique_id

            dehydrated["forms"] = []
            for form in module.forms:
                form_unique_id = form.unique_id
                form = Form.get_form(form_unique_id)
                form_jvalue = {
                    "xmlns": form.xmlns,
                    "name": form.name,
                    "questions": form.get_questions(langs, include_translations=True),
                    "unique_id": form_unique_id,
                }
                dehydrated["forms"].append(form_jvalue)
            return dehydrated
        except Exception as e:
            return {"error": unicode(e)}
Example #11
0
def keyword_uses_form_that_requires_case(survey_keyword):
    for action in survey_keyword.actions:
        if action.action in [METHOD_SMS_SURVEY, METHOD_STRUCTURED_SMS]:
            form = Form.get_form(action.form_unique_id)
            if form.requires_case():
                return True
    return False
Example #12
0
def get_form_data_schema(request, domain, form_unique_id):
    """Get data schema

    One of `app_id` or `form_unique_id` is required. `app_id` is ignored
    if `form_unique_id` is provided.

    :returns: A list of data source schema definitions. A data source schema
    definition is a dictionary. For details on the content of the dictionary,
    see https://github.com/dimagi/Vellum/blob/master/src/datasources.js
    """
    data = []

    try:
        form, app = Form.get_form(form_unique_id, and_app=True)
    except ResourceConflict:
        raise Http404()

    if app.domain != domain:
        raise Http404()

    try:
        data.append(get_session_schema(form))
        if form.requires_case() or is_usercase_in_use(domain):
            data.append(get_casedb_schema(form))
    except Exception:
        logger.exception("schema error")
        return HttpResponseBadRequest("schema error, see log for details")

    data.extend(
        sorted(item_lists_by_domain(domain), key=lambda x: x['name'].lower())
    )
    kw = {}
    if "pretty" in request.GET:
        kw["indent"] = 2
    return HttpResponse(json.dumps(data, **kw))
Example #13
0
def create_data_source_from_app(request, domain):
    if request.method == 'POST':
        form = ConfigurableDataSourceFromAppForm(domain, request.POST)
        if form.is_valid():
            # save config
            app_source = form.app_source_helper.get_app_source(
                form.cleaned_data)
            app = Application.get(app_source.application)
            if app_source.source_type == 'case':
                data_source = get_case_data_source(app, app_source.source)
                data_source.save()
                messages.success(
                    request,
                    _(u"Data source created for '{}'".format(
                        app_source.source)))
            else:
                assert app_source.source_type == 'form'
                xform = Form.get_form(app_source.source)
                data_source = get_form_data_source(app, xform)
                data_source.save()
                messages.success(
                    request,
                    _(u"Data source created for '{}'".format(
                        xform.default_name())))

            return HttpResponseRedirect(
                reverse('edit_configurable_data_source',
                        args=[domain, data_source._id]))
    else:
        form = ConfigurableDataSourceFromAppForm(domain)
    context = _shared_context(domain)
    context['sources_map'] = form.app_source_helper.all_sources
    context['form'] = form
    return render(request, 'userreports/data_source_from_app.html', context)
Example #14
0
    def post(self, request, *args, **kwargs):
        if self.form.is_valid():
            app_source = self.form.app_source_helper.get_app_source(
                self.form.cleaned_data)
            app = Application.get(app_source.application)
            if app_source.source_type == 'case':
                data_source = get_case_data_source(app, app_source.source)
                data_source.save()
                messages.success(
                    request,
                    _(u"Data source created for '{}'".format(
                        app_source.source)))
            else:
                assert app_source.source_type == 'form'
                xform = Form.get_form(app_source.source)
                data_source = get_form_data_source(app, xform)
                data_source.save()
                messages.success(
                    request,
                    _(u"Data source created for '{}'".format(
                        xform.default_name())))

            return HttpResponseRedirect(
                reverse(EditDataSourceView.urlname,
                        args=[self.domain, data_source._id]))
        return self.get(request, *args, **kwargs)
Example #15
0
def get_form_name(form_unique_id):
    try:
        form = Form.get_form(form_unique_id)
    except ResourceNotFound:
        return _("[unknown]")

    return form.full_path_name
Example #16
0
def get_form(form_unique_id, include_app_module=False):
    form = Form.get_form(form_unique_id)
    if include_app_module:
        app = form.get_app()
        module = form.get_module()
        return (app, module, form)
    else:
        return form
Example #17
0
def form_casexml(request, domain, form_unique_id):
    try:
        form, app = Form.get_form(form_unique_id, and_app=True)
    except ResourceNotFound:
        raise Http404()
    if domain != app.domain:
        raise Http404()
    return HttpResponse(form.create_casexml())
Example #18
0
def get_form(form_unique_id, include_app_module=False):
    form = Form.get_form(form_unique_id)
    if include_app_module:
        app = form.get_app()
        module = form.get_module()
        return (app, module, form)
    else:
        return form
Example #19
0
def form_casexml(request, domain, form_unique_id):
    try:
        form, app = Form.get_form(form_unique_id, and_app=True)
    except ResourceNotFound:
        raise Http404()
    if domain != app.domain:
        raise Http404()
    return HttpResponse(form.create_casexml())
    def test_update_form_references_case_list_form(self):
        app = Application.new_app('domain', 'Foo')
        app.modules.append(Module(forms=[Form()]))
        app.modules.append(Module(forms=[Form()]))
        app.build_spec = BuildSpec.from_string('2.7.0/latest')
        app.get_module(0).get_form(0).source = get_simple_form(
            xmlns='xmlns-0.0')
        app.get_module(1).get_form(0).source = get_simple_form(xmlns='xmlns-1')

        original_form_id = app.get_module(1).get_form(0).unique_id
        app.get_module(0).case_list_form.form_id = original_form_id

        copy = Application.from_source(app.export_json(dump_json=False),
                                       'domain')
        new_form_id = copy.get_module(1).get_form(0).unique_id
        self.assertNotEqual(original_form_id, new_form_id)
        self.assertEqual(new_form_id,
                         copy.get_module(0).case_list_form.form_id)
Example #21
0
 def _resolve_from_template(self, template, query_context):
     # todo: support other types and options
     assert template.type == 'form'
     startdate, enddate = get_daterange_start_end_dates(template.time_range)
     xmlns = Form.get_form(template.source_id).xmlns
     return FormES().user_id(query_context.user._id).xmlns([xmlns]).submitted(
         gte=startdate,
         lte=enddate,
     ).size(0).count()
Example #22
0
 def _resolve_from_template(self, template, query_context):
     # todo: support other types and options
     assert template.type == 'form'
     startdate, enddate = get_daterange_start_end_dates(template.time_range)
     xmlns = Form.get_form(template.source_id).xmlns
     return FormES().user_id(query_context.user._id).xmlns(
         [xmlns]).submitted(
             gte=startdate,
             lte=enddate,
         ).size(0).count()
Example #23
0
 def clean_form_unique_id(self):
     value = self.cleaned_data.get("form_unique_id")
     if value is None:
         raise ValidationError(_("Please create a form first, and then add a keyword for it."))
     try:
         form = CCHQForm.get_form(value)
         app = form.get_app()
         assert app.domain == self._cchq_domain
     except Exception:
         raise ValidationError(_("Invalid form chosen."))
     return value
Example #24
0
 def _resolve_from_template(self, template, query_context):
     # todo: support other types and options
     assert template.type == 'form'
     startdate, enddate = get_daterange_start_end_dates(template.time_range)
     xmlns = Form.get_form(template.source_id).xmlns
     return FormData.objects.filter(
         user_id=query_context.user._id,
         xmlns=xmlns,
         received_on__gte=startdate,
         received_on__lt=enddate,
     ).count()
Example #25
0
 def search_form_by_id_response(self):
     """
     Returns a dict of {"id": [form unique id], "text": [full form path]}
     """
     form_unique_id = self.search_term
     try:
         form = Form.get_form(form_unique_id)
         assert form.get_app().domain == self.domain
         return {"text": form.full_path_name, "id": form_unique_id}
     except:
         return {}
Example #26
0
def validate_form_unique_id(form_unique_id, domain):
    error_msg = _('Invalid form chosen.')
    try:
        form = CCHQForm.get_form(form_unique_id)
        app = form.get_app()
    except Exception:
        raise ValidationError(error_msg)

    if app.domain != domain:
        raise ValidationError(error_msg)

    return form_unique_id
Example #27
0
    def get_memoized_app_module_form(self, domain):
        try:
            form = Form.get_form(self.form_unique_id)
            app = form.get_app()
            module = form.get_module()
        except (ResourceNotFound, XFormIdNotUnique):
            return None, None, None, None

        if app.domain != domain:
            return None, None, None, None

        return app, module, form, form_requires_input(form)
Example #28
0
def validate_form_unique_id(form_unique_id, domain):
    error_msg = _('Invalid form chosen.')
    try:
        form = CCHQForm.get_form(form_unique_id)
        app = form.get_app()
    except Exception:
        raise ValidationError(error_msg)

    if app.domain != domain:
        raise ValidationError(error_msg)

    return form_unique_id
Example #29
0
def get_app_module_form(call_log_entry, logged_subevent):
    """
    Returns (app, module, form, error)
    """
    try:
        form = Form.get_form(call_log_entry.form_unique_id)
        app = form.get_app()
        module = form.get_module()
        return (app, module, form, False)
    except:
        log_error(MessagingEvent.ERROR_CANNOT_FIND_FORM, call_log_entry, logged_subevent)
        return (None, None, None, True)
Example #30
0
 def clean(self):
     cleaned_data = super(ConfigurableFormDataSourceFromAppForm, self).clean()
     app = Application.get(cleaned_data['app_id'])
     form = Form.get_form(cleaned_data['form_id'])
     if form.get_app()._id != app._id:
         raise ValidationError(_('Form name {} not found in application {}').format(
             form.default_name(),
             app.name
         ))
     self.app = app
     self.form = form
     return cleaned_data
Example #31
0
def get_app_module_form(form_unique_id, logged_subevent=None):
    """
    Returns (app, module, form, error, error_code)
    """
    try:
        form = Form.get_form(form_unique_id)
        app = form.get_app()
        module = form.get_module()
        return (app, module, form, False, None)
    except:
        log_error(MessagingEvent.ERROR_CANNOT_FIND_FORM, logged_subevent)
        return (None, None, None, True, MSG_FORM_NOT_FOUND)
Example #32
0
    def get_memoized_app_module_form(self, domain):
        try:
            form = Form.get_form(self.form_unique_id)
            app = form.get_app()
            module = form.get_module()
        except (ResourceNotFound, XFormIdNotUnique):
            return None, None, None

        if app.domain != domain:
            return None, None, None

        return app, module, form
Example #33
0
def get_app_module_form(form_unique_id, logged_subevent=None):
    """
    Returns (app, module, form, error, error_code)
    """
    try:
        form = Form.get_form(form_unique_id)
        app = form.get_app()
        module = form.get_module()
        return (app, module, form, False, None)
    except:
        log_error(MessagingEvent.ERROR_CANNOT_FIND_FORM, logged_subevent)
        return (None, None, None, True, MSG_FORM_NOT_FOUND)
Example #34
0
def get_app_module_form(call_log_entry, logged_subevent):
    """
    Returns (app, module, form, error)
    """
    try:
        form = Form.get_form(call_log_entry.form_unique_id)
        app = form.get_app()
        module = form.get_module()
        return (app, module, form, False)
    except:
        log_error(MessagingEvent.ERROR_CANNOT_FIND_FORM, call_log_entry,
                  logged_subevent)
        return (None, None, None, True)
Example #35
0
 def clean_form_unique_id(self):
     value = self.cleaned_data.get("form_unique_id")
     if value is None:
         raise ValidationError(
             _("Please create a form first, and then add a keyword for it.")
         )
     try:
         form = CCHQForm.get_form(value)
         app = form.get_app()
         assert app.domain == self._cchq_domain
     except Exception:
         raise ValidationError(_("Invalid form chosen."))
     return value
Example #36
0
 def search_form_by_id_response(self):
     """
     Returns a dict of {"id": [form unique id], "text": [full form path]}
     """
     form_unique_id = self.search_term
     try:
         form = Form.get_form(form_unique_id)
         assert form.get_app().domain == self.domain
         return {
             'text': form.full_path_name,
             'id': form_unique_id,
         }
     except:
         return {}
Example #37
0
def get_form_name(form_unique_id):
    form = Form.get_form(form_unique_id)
    app = form.get_app()
    module = form.get_module()
    lang = app.langs[0]
    try:
        module_name = module.name[lang]
    except Exception:
        module_name = module.name.items()[0][1]
    try:
        form_name = form.name[lang]
    except Exception:
        form_name = form.name.items()[0][1]
    return app.name + "/" + module_name + "/" + form_name
Example #38
0
def get_form_name(form_unique_id):
    form = Form.get_form(form_unique_id)
    app = form.get_app()
    module = form.get_module()
    lang = app.langs[0]
    try:
        module_name = module.name[lang]
    except Exception:
        module_name = module.name.items()[0][1]
    try:
        form_name = form.name[lang]
    except Exception:
        form_name = form.name.items()[0][1]
    return app.name + "/" + module_name + "/" + form_name
Example #39
0
    def setUpClass(cls):
        super(ExportsFormsAnalyticsTest, cls).setUpClass()
        from casexml.apps.case.tests.util import delete_all_xforms
        from corehq.apps.app_manager.models import Application, Module, Form
        delete_all_xforms()

        with trap_extra_setup(ConnectionError,
                              msg="cannot connect to elasicsearch"):
            cls.es = get_es_new()
            initialize_index_and_mapping(cls.es, XFORM_INDEX_INFO)

        cls.domain = 'exports_forms_analytics_domain'
        cls.app_id_1 = 'a' + uuid.uuid4().hex
        cls.app_id_2 = 'b' + uuid.uuid4().hex
        cls.xmlns_1 = 'my://crazy.xmlns/'
        cls.xmlns_2 = 'my://crazy.xmlns/app'
        cls.apps = [
            Application(_id=cls.app_id_2,
                        domain=cls.domain,
                        modules=[Module(forms=[Form(xmlns=cls.xmlns_2)])])
        ]
        for app in cls.apps:
            app.save()
        cls.forms = [
            create_form_for_test(domain=cls.domain,
                                 app_id=cls.app_id_1,
                                 xmlns=cls.xmlns_1,
                                 save=False),
            create_form_for_test(domain=cls.domain,
                                 app_id=cls.app_id_1,
                                 xmlns=cls.xmlns_1,
                                 save=False),
            create_form_for_test(domain=cls.domain,
                                 app_id=cls.app_id_2,
                                 xmlns=cls.xmlns_2,
                                 save=False),
        ]
        cls.error_forms = [
            create_form_for_test(domain=cls.domain,
                                 state=XFormInstance.ERROR,
                                 save=False)
        ]
        cls.all_forms = cls.forms + cls.error_forms
        for form in cls.all_forms:
            elastic_form = transform_xform_for_elasticsearch(form.to_json())
            send_to_elasticsearch('forms', elastic_form)

        cls.es.indices.refresh(XFORM_INDEX_INFO.alias)
Example #40
0
    def __init__(self, domain, app, source_type, source_id):
        assert (source_type in ['case', 'form'])

        self.domain = domain
        self.app = app
        self.source_type = source_type
        # source_id is a case type of form id
        self.source_id = source_id
        if self.source_type == 'form':
            self.source_form = Form.get_form(self.source_id)
            self.source_xform = XForm(self.source_form.source)
        if self.source_type == 'case':
            prop_map = get_case_properties(
                self.app, [self.source_id], defaults=DEFAULT_CASE_PROPERTY_DATATYPES.keys()
            )
            self.case_properties = sorted(set(prop_map[self.source_id]) | {'closed'})
Example #41
0
def rename_language(request, domain, form_unique_id):
    old_code = request.POST.get('oldCode')
    new_code = request.POST.get('newCode')
    try:
        form, app = Form.get_form(form_unique_id, and_app=True)
    except ResourceConflict:
        raise Http404()
    if app.domain != domain:
        raise Http404()
    try:
        form.rename_xform_language(old_code, new_code)
        app.save()
        return HttpResponse(json.dumps({"status": "ok"}))
    except XFormException as e:
        response = HttpResponse(json.dumps({'status': 'error', 'message': unicode(e)}), status=409)
        return response
Example #42
0
def rename_language(request, domain, form_unique_id):
    old_code = request.POST.get("oldCode")
    new_code = request.POST.get("newCode")
    try:
        form, app = Form.get_form(form_unique_id, and_app=True)
    except ResourceConflict:
        raise Http404()
    if app.domain != domain:
        raise Http404()
    try:
        form.rename_xform_language(old_code, new_code)
        app.save()
        return HttpResponse(json.dumps({"status": "ok"}))
    except XFormException as e:
        response = HttpResponse(json.dumps({"status": "error", "message": unicode(e)}), status=409)
        return response
Example #43
0
    def test_repeat_subcases_schema_generation(self):
        module = Module(case_type='child', _parent=Application())
        form = Form().with_id(0, module)
        form.actions.subcases = [
            OpenSubCaseAction(
                repeat_context='/data/repeat',
                case_properties={
                    'weight':
                    ConditionalCaseUpdate(
                        question_path='/data/repeat/group/weight'),
                },
                subcase_index=0,
                _nest=True).with_id(0, None),
            OpenSubCaseAction(
                repeat_context='/data/repeat',
                case_properties={
                    'height':
                    ConditionalCaseUpdate(question_path='/data/repeat/height'),
                },
                subcase_index=1,
                _nest=True).with_id(1, None),
            OpenSubCaseAction(
                repeat_context='/data/repeat/nested_repeat',
                case_properties={
                    'age':
                    ConditionalCaseUpdate(
                        question_path='/data/repeat/nested_repeat/age'),
                },
                subcase_index=2,
                _nest=False).with_id(2, None),
        ]

        schema = FormExportDataSchema._add_export_items_for_cases(
            ExportGroupSchema(path=MAIN_TABLE),
            [form],
            ['/data/repeat', '/data/nested_repeat'],
        )[0]

        self.assertEqual(len(schema.group_schemas), len(form.actions.subcases))
        for group_schema, action in zip(schema.group_schemas,
                                        form.actions.subcases):
            base_path = 'form.{}'.format(action.repeat_context[6:].replace(
                '/', '.'))
            if action._nest:
                base_path += '.{}'.format(action.form_element_name)
            self._check_subcase_repeat_group_schema(
                group_schema, list(action.case_properties), base_path)
Example #44
0
def get_form_name(form_unique_id):
    try:
        form = Form.get_form(form_unique_id)
    except ResourceNotFound:
        return _("[unknown]")
    app = form.get_app()
    module = form.get_module()
    lang = app.langs[0]
    try:
        module_name = module.name[lang]
    except Exception:
        module_name = module.name.items()[0][1]
    try:
        form_name = form.name[lang]
    except Exception:
        form_name = form.name.items()[0][1]
    return app.name + "/" + module_name + "/" + form_name
Example #45
0
def get_form_name(form_unique_id):
    try:
        form = Form.get_form(form_unique_id)
    except ResourceNotFound:
        return _("[unknown]")
    app = form.get_app()
    module = form.get_module()
    lang = app.langs[0]
    try:
        module_name = module.name[lang]
    except Exception:
        module_name = module.name.items()[0][1]
    try:
        form_name = form.name[lang]
    except Exception:
        form_name = form.name.items()[0][1]
    return app.name + "/" + module_name + "/" + form_name
Example #46
0
    def __init__(self, domain, app, source_type, source_id):
        assert (source_type in ['case', 'form'])

        self.domain = domain
        self.app = app
        self.source_type = source_type
        # source_id is a case type of form id
        self.source_id = source_id
        if self.source_type == 'form':
            self.source_form = Form.get_form(self.source_id)
            self.source_xform = XForm(self.source_form.source)
        if self.source_type == 'case':
            prop_map = get_case_properties(
                self.app, [self.source_id],
                defaults=DEFAULT_CASE_PROPERTY_DATATYPES.keys())
            self.case_properties = sorted(
                set(prop_map[self.source_id]) | {'closed'})
Example #47
0
    def __init__(self, domain, app, source_type, source_id):
        assert (source_type in ['case', 'form'])

        self.domain = domain
        self.app = app
        self.source_type = source_type
        # source_id is a case type of form id
        self.source_id = source_id
        if self.source_type == 'form':
            self.source_form = Form.get_form(self.source_id)
            self.source_xform = XForm(self.source_form.source)
        if self.source_type == 'case':
            property_builder = ParentCasePropertyBuilder(
                self.app, DEFAULT_CASE_PROPERTY_DATATYPES.keys()
            )
            self.case_properties = list(
                property_builder.get_properties(self.source_id) | {'closed'}
            )
Example #48
0
    def post(self, request, *args, **kwargs):
        if self.form.is_valid():
            app_source = self.form.app_source_helper.get_app_source(self.form.cleaned_data)
            app = Application.get(app_source.application)
            if app_source.source_type == 'case':
                data_source = get_case_data_source(app, app_source.source)
                data_source.save()
                messages.success(request, _(u"Data source created for '{}'".format(app_source.source)))
            else:
                assert app_source.source_type == 'form'
                xform = Form.get_form(app_source.source)
                data_source = get_form_data_source(app, xform)
                data_source.save()
                messages.success(request, _(u"Data source created for '{}'".format(xform.default_name())))

            return HttpResponseRedirect(reverse(
                EditDataSourceView.urlname, args=[self.domain, data_source._id]
            ))
        return self.get(request, *args, **kwargs)
Example #49
0
 def container_fieldset(self):
     source_name = ''
     if self.source_type == 'case':
         source_name = self.report_source_id
     if self.source_type == 'form':
         source_name = Form.get_form(self.report_source_id).default_name()
     return crispy.Fieldset(
         '',
         crispy.Fieldset(
             _legend(
                 _("Rows"),
                 _('This report will show one row for each {name} {source}').format(
                     name=source_name, source=self.source_type
                 )
             )
         ),
         self.column_fieldset,
         self.filter_fieldset
     )
Example #50
0
def xform_display(request, domain, form_unique_id):
    try:
        form, app = Form.get_form(form_unique_id, and_app=True)
    except ResourceNotFound:
        raise Http404()
    if domain != app.domain:
        raise Http404()
    langs = [request.GET.get('lang')] + app.langs

    questions = form.get_questions(langs,
                                   include_triggers=True,
                                   include_groups=True)

    if request.GET.get('format') == 'html':
        questions = [FormQuestionResponse(q) for q in questions]
        return render(request, "app_manager/xform_display.html",
                      {'questions': questions_in_hierarchy(questions)})
    else:
        return json_response(questions)
Example #51
0
def xform_display(request, domain, form_unique_id):
    try:
        form, app = Form.get_form(form_unique_id, and_app=True)
    except ResourceNotFound:
        raise Http404()
    if domain != app.domain:
        raise Http404()
    langs = [request.GET.get('lang')] + app.langs

    questions = form.get_questions(langs, include_triggers=True,
                                   include_groups=True)

    if request.GET.get('format') == 'html':
        questions = [FormQuestionResponse(q) for q in questions]

        return render(request, 'app_manager/v1/xform_display.html', {
            'questions': questions_in_hierarchy(questions)
        })
    else:
        return json_response(questions)
Example #52
0
    def setUpClass(cls):
        from casexml.apps.case.tests.util import delete_all_xforms
        from corehq.apps.app_manager.models import Application, Module, Form
        delete_all_xforms()

        with trap_extra_setup(ConnectionError,
                              msg="cannot connect to elasicsearch"):
            cls.es = get_es_new()
            initialize_index_and_mapping(cls.es, XFORM_INDEX_INFO)

        cls.domain = 'exports_forms_analytics_domain'
        cls.app_id_1 = 'a' + uuid.uuid4().hex
        cls.app_id_2 = 'b' + uuid.uuid4().hex
        cls.xmlns_1 = 'my://crazy.xmlns/'
        cls.xmlns_2 = 'my://crazy.xmlns/app'
        cls.apps = [
            Application(_id=cls.app_id_2,
                        domain=cls.domain,
                        modules=[Module(forms=[Form(xmlns=cls.xmlns_2)])])
        ]
        for app in cls.apps:
            app.save()
        cls.forms = [
            XFormInstance(domain=cls.domain,
                          app_id=cls.app_id_1,
                          xmlns=cls.xmlns_1),
            XFormInstance(domain=cls.domain,
                          app_id=cls.app_id_1,
                          xmlns=cls.xmlns_1),
            XFormInstance(domain=cls.domain,
                          app_id=cls.app_id_2,
                          xmlns=cls.xmlns_2),
        ]
        cls.error_forms = [XFormError(domain=cls.domain)]
        cls.all_forms = cls.forms + cls.error_forms
        for form in cls.all_forms:
            form.save()
            send_to_elasticsearch('forms', form.to_json())

        cls.es.indices.refresh(XFORM_INDEX_INFO.index)
        update_analytics_indexes()
Example #53
0
def get_form_data_schema(request, domain, form_unique_id):
    """Get data schema

    One of `app_id` or `form_unique_id` is required. `app_id` is ignored
    if `form_unique_id` is provided.

    :returns: A list of data source schema definitions. A data source schema
    definition is a dictionary. For details on the content of the dictionary,
    see https://github.com/dimagi/Vellum/blob/master/src/datasources.js
    """
    data = []

    try:
        form, app = Form.get_form(form_unique_id, and_app=True)
    except ResourceConflict:
        raise Http404()

    if app.domain != domain:
        raise Http404()

    try:
        data.append(get_session_schema(form))
        if form.requires_case() or is_usercase_in_use(domain):
            data.append(get_casedb_schema(form))
    except AppManagerException as e:
        notify_exception(request, message=str(e))
        return HttpResponseBadRequest(
            str(e) or _("There is an error in the case management of your application. "
            "Please fix the error to see case properties in this tree")
        )
    except Exception as e:
        notify_exception(request, message=six.text_type(e))
        return HttpResponseBadRequest("schema error, see log for details")

    data.extend(
        sorted(item_lists_by_domain(domain), key=lambda x: x['name'].lower())
    )
    kw = {}
    if "pretty" in request.GET:
        kw["indent"] = 2
    return HttpResponse(json.dumps(data, **kw))
Example #54
0
def start_session_from_keyword(survey_keyword, verified_number):
    try:
        form_unique_id = survey_keyword.form_unique_id
        form = Form.get_form(form_unique_id)
        app = form.get_app()
        module = form.get_module()
        
        if verified_number.owner_doc_type == "CommCareCase":
            case_id = verified_number.owner_id
        else:
            #TODO: Need a way to choose the case when it's a user that's playing the form
            case_id = None
        
        session, responses = start_session(verified_number.domain, verified_number.owner, app, module, form, case_id)
        
        if len(responses) > 0:
            message = format_message_list(responses)
            send_sms_to_verified_number(verified_number, message)
        
    except Exception:
        logging.exception("Exception while starting survey for keyword %s, domain %s" % (survey_keyword.keyword, verified_number.domain))
 def setUp(self):
     self.form = Form()
Example #56
0
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers, logged_event):
    if reminder.callback_try_count > 0:
        # Handle timeouts
        if handler.submit_partial_forms and (
            reminder.callback_try_count == len(reminder.current_event.callback_timeout_intervals)
        ):
            # Submit partial form completions
            for session_id in reminder.xforms_session_ids:
                submit_unfinished_form(session_id, handler.include_case_side_effects)
        else:
            # Resend current question
            for session_id in reminder.xforms_session_ids:
                session = get_session_by_session_id(session_id)
                if session.end_time is None:
                    vn = VerifiedNumber.view(
                        "sms/verified_number_by_owner_id", key=session.connection_id, include_docs=True
                    ).first()
                    if vn is not None:
                        metadata = MessageMetadata(
                            workflow=get_workflow(handler),
                            reminder_id=reminder._id,
                            xforms_session_couch_id=session._id,
                        )
                        resp = current_question(session_id)
                        send_sms_to_verified_number(vn, resp.event.text_prompt, metadata)
    else:
        reminder.xforms_session_ids = []
        domain_obj = Domain.get_by_name(reminder.domain, strict=True)

        # Get the app, module, and form
        try:
            form_unique_id = reminder.current_event.form_unique_id
            form = Form.get_form(form_unique_id)
            app = form.get_app()
            module = form.get_module()
        except Exception:
            logged_event.error(MessagingEvent.ERROR_CANNOT_FIND_FORM)
            return

        # Start a touchforms session for each recipient
        for recipient in recipients:
            logged_subevent = logged_event.create_subevent(handler, reminder, recipient)

            verified_number, unverified_number = get_recipient_phone_number(reminder, recipient, verified_numbers)

            no_verified_number = verified_number is None
            cant_use_unverified_number = (
                unverified_number is None or not domain_obj.send_to_duplicated_case_numbers or form_requires_input(form)
            )
            if no_verified_number and cant_use_unverified_number:
                logged_subevent.error(MessagingEvent.ERROR_NO_TWO_WAY_PHONE_NUMBER)
                continue

            key = "start-sms-survey-for-contact-%s" % recipient.get_id
            with CriticalSection([key], timeout=60):
                # Get the case to submit the form against, if any
                if isinstance(recipient, CommCareCase) and not handler.force_surveys_to_use_triggered_case:
                    case_id = recipient.get_id
                else:
                    case_id = reminder.case_id

                if form.requires_case() and not case_id:
                    logged_subevent.error(MessagingEvent.ERROR_NO_CASE_GIVEN)
                    continue

                # Close all currently open sessions
                SQLXFormsSession.close_all_open_sms_sessions(reminder.domain, recipient.get_id)

                # Start the new session
                try:
                    session, responses = start_session(
                        reminder.domain,
                        recipient,
                        app,
                        module,
                        form,
                        case_id,
                        case_for_case_submission=handler.force_surveys_to_use_triggered_case,
                    )
                except TouchformsError as e:
                    human_readable_message = e.response_data.get("human_readable_message", None)

                    logged_subevent.error(
                        MessagingEvent.ERROR_TOUCHFORMS_ERROR, additional_error_text=human_readable_message
                    )

                    if touchforms_error_is_config_error(e):
                        # Don't reraise the exception because this means there are configuration
                        # issues with the form that need to be fixed
                        continue
                    else:
                        # Reraise the exception so that the framework retries it again later
                        raise
                except Exception as e:
                    logged_subevent.error(MessagingEvent.ERROR_TOUCHFORMS_ERROR)
                    # Reraise the exception so that the framework retries it again later
                    raise
                session.survey_incentive = handler.survey_incentive
                session.workflow = get_workflow(handler)
                session.reminder_id = reminder._id
                session.save()

            reminder.xforms_session_ids.append(session.session_id)
            logged_subevent.xforms_session = session
            logged_subevent.save()

            # Send out first message
            if len(responses) > 0:
                message = format_message_list(responses)
                metadata = MessageMetadata(
                    workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id
                )
                if verified_number:
                    send_sms_to_verified_number(verified_number, message, metadata)
                else:
                    send_sms(reminder.domain, recipient, unverified_number, message, metadata)

            logged_subevent.completed()
Example #57
0
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers,
                          logged_event):
    if reminder.callback_try_count > 0:
        # Handle timeouts
        if handler.submit_partial_forms and (
                reminder.callback_try_count == len(
                    reminder.current_event.callback_timeout_intervals)):
            # Submit partial form completions
            for session_id in reminder.xforms_session_ids:
                submit_unfinished_form(session_id,
                                       handler.include_case_side_effects)
        else:
            # Resend current question
            for session_id in reminder.xforms_session_ids:
                session = get_session_by_session_id(session_id)
                if session.end_time is None:
                    vn = VerifiedNumber.view("sms/verified_number_by_owner_id",
                                             key=session.connection_id,
                                             include_docs=True).first()
                    if vn is not None:
                        metadata = MessageMetadata(
                            workflow=get_workflow(handler),
                            reminder_id=reminder._id,
                            xforms_session_couch_id=session._id,
                        )
                        resp = current_question(session_id)
                        send_sms_to_verified_number(vn, resp.event.text_prompt,
                                                    metadata)
    else:
        reminder.xforms_session_ids = []
        domain_obj = Domain.get_by_name(reminder.domain, strict=True)

        # Get the app, module, and form
        try:
            form_unique_id = reminder.current_event.form_unique_id
            form = Form.get_form(form_unique_id)
            app = form.get_app()
            module = form.get_module()
        except Exception:
            logged_event.error(MessagingEvent.ERROR_CANNOT_FIND_FORM)
            return

        # Start a touchforms session for each recipient
        for recipient in recipients:
            logged_subevent = logged_event.create_subevent(
                handler, reminder, recipient)

            verified_number, unverified_number = get_recipient_phone_number(
                reminder, recipient, verified_numbers)

            no_verified_number = verified_number is None
            cant_use_unverified_number = (
                unverified_number is None
                or not domain_obj.send_to_duplicated_case_numbers
                or form_requires_input(form))
            if no_verified_number and cant_use_unverified_number:
                logged_subevent.error(
                    MessagingEvent.ERROR_NO_TWO_WAY_PHONE_NUMBER)
                continue

            key = "start-sms-survey-for-contact-%s" % recipient.get_id
            with CriticalSection([key], timeout=60):
                # Get the case to submit the form against, if any
                if (isinstance(recipient, CommCareCase)
                        and not handler.force_surveys_to_use_triggered_case):
                    case_id = recipient.get_id
                else:
                    case_id = reminder.case_id

                if form.requires_case() and not case_id:
                    logged_subevent.error(MessagingEvent.ERROR_NO_CASE_GIVEN)
                    continue

                # Close all currently open sessions
                SQLXFormsSession.close_all_open_sms_sessions(
                    reminder.domain, recipient.get_id)

                # Start the new session
                try:
                    session, responses = start_session(
                        reminder.domain,
                        recipient,
                        app,
                        module,
                        form,
                        case_id,
                        case_for_case_submission=handler.
                        force_surveys_to_use_triggered_case)
                except TouchformsError as e:
                    human_readable_message = e.response_data.get(
                        'human_readable_message', None)

                    logged_subevent.error(
                        MessagingEvent.ERROR_TOUCHFORMS_ERROR,
                        additional_error_text=human_readable_message)

                    if touchforms_error_is_config_error(e):
                        # Don't reraise the exception because this means there are configuration
                        # issues with the form that need to be fixed
                        continue
                    else:
                        # Reraise the exception so that the framework retries it again later
                        raise
                except Exception as e:
                    logged_subevent.error(
                        MessagingEvent.ERROR_TOUCHFORMS_ERROR)
                    # Reraise the exception so that the framework retries it again later
                    raise
                session.survey_incentive = handler.survey_incentive
                session.workflow = get_workflow(handler)
                session.reminder_id = reminder._id
                session.save()

            reminder.xforms_session_ids.append(session.session_id)
            logged_subevent.xforms_session = session
            logged_subevent.save()

            # Send out first message
            if len(responses) > 0:
                message = format_message_list(responses)
                metadata = MessageMetadata(
                    workflow=get_workflow(handler),
                    reminder_id=reminder._id,
                    xforms_session_couch_id=session._id,
                )
                if verified_number:
                    send_sms_to_verified_number(verified_number, message,
                                                metadata)
                else:
                    send_sms(reminder.domain, recipient, unverified_number,
                             message, metadata)

            logged_subevent.completed()
Example #58
0
def structured_sms_handler(verified_number, text):

    # Circular Import
    from corehq.apps.reminders.models import SurveyKeyword, FORM_TYPE_ALL_AT_ONCE

    text = text.strip()
    if text == "":
        return False
    for survey_keyword in SurveyKeyword.get_all(verified_number.domain):
        if survey_keyword.form_type == FORM_TYPE_ALL_AT_ONCE:
            if survey_keyword.delimiter is not None:
                args = text.split(survey_keyword.delimiter)
            else:
                args = text.split()

            keyword = args[0].strip().upper()
            if keyword != survey_keyword.keyword.upper():
                continue

            try:
                error_occurred = False
                error_msg = ""
                form_complete = False

                # Close any open sessions
                close_open_sessions(verified_number.domain, verified_number.owner_id)

                # Start the session
                form = Form.get_form(survey_keyword.form_unique_id)
                app = form.get_app()
                module = form.get_module()

                if verified_number.owner_doc_type == "CommCareCase":
                    case_id = verified_number.owner_id
                else:
                    # TODO: Need a way to choose the case when it's a user that's playing the form
                    case_id = None

                session, responses = start_session(
                    verified_number.domain,
                    verified_number.owner,
                    app,
                    module,
                    form,
                    case_id=case_id,
                    yield_responses=True,
                )
                assert len(responses) > 0, "There should be at least one response."

                current_question = responses[-1]
                form_complete = is_form_complete(current_question)

                if not form_complete:
                    if survey_keyword.use_named_args:
                        # Arguments in the sms are named
                        xpath_answer = {}  # Dictionary of {xpath : answer}
                        for answer in args[1:]:
                            answer = answer.strip()
                            answer_upper = answer.upper()
                            if survey_keyword.named_args_separator is not None:
                                # A separator is used for naming arguments; for example, the "=" in "register name=joe age=25"
                                answer_parts = answer.partition(survey_keyword.named_args_separator)
                                if answer_parts[1] != survey_keyword.named_args_separator:
                                    error_occurred = True
                                    error_msg = "ERROR: Expected name and value to be joined by" + (
                                        " '%s'" % survey_keyword.named_args_separator
                                    )
                                    break
                                else:
                                    arg_name = answer_parts[0].upper().strip()
                                    xpath = survey_keyword.named_args.get(arg_name, None)
                                    if xpath is not None:
                                        if xpath in xpath_answer:
                                            error_occurred = True
                                            error_msg = "ERROR: More than one answer found for" + (" '%s'" % arg_name)
                                            break

                                        xpath_answer[xpath] = answer_parts[2].strip()
                                    else:
                                        # Ignore unexpected named arguments
                                        pass
                            else:
                                # No separator is used for naming arguments; for example, "update a100 b34 c5"
                                matches = 0
                                for k, v in survey_keyword.named_args.items():
                                    if answer_upper.startswith(k):
                                        matches += 1
                                        if matches > 1:
                                            error_occurred = True
                                            error_msg = "ERROR: More than one question matches" + (" '%s'" % answer)
                                            break

                                        if v in xpath_answer:
                                            error_occurred = True
                                            error_msg = "ERROR: More than one answer found for" + (" '%s'" % k)
                                            break

                                        xpath_answer[v] = answer[len(k) :].strip()

                                if matches == 0:
                                    # Ignore unexpected named arguments
                                    pass

                            if error_occurred:
                                break

                        # Go through each question in the form, answering only the questions that the sms has answers for
                        while not form_complete and not error_occurred:
                            if current_question.is_error:
                                error_occurred = True
                                error_msg = current_question.text_prompt or "ERROR: Internal server error"
                                break

                            xpath = current_question.event._dict["binding"]
                            if xpath in xpath_answer:
                                valid, answer, _error_msg = validate_answer(current_question.event, xpath_answer[xpath])
                                if not valid:
                                    error_occurred = True
                                    error_msg = "ERROR: " + _error_msg
                                    break
                                responses = _get_responses(
                                    verified_number.domain, verified_number.owner_id, answer, yield_responses=True
                                )
                            else:
                                responses = _get_responses(
                                    verified_number.domain, verified_number.owner_id, "", yield_responses=True
                                )

                            current_question = responses[-1]
                            if is_form_complete(current_question):
                                form_complete = True
                    else:
                        # Arguments in the sms are not named; pass each argument to each question in order
                        for answer in args[1:]:
                            if form_complete:
                                # Form is complete, ignore remaining answers
                                break

                            if current_question.is_error:
                                error_occurred = True
                                error_msg = current_question.text_prompt or "ERROR: Internal server error"
                                break

                            valid, answer, _error_msg = validate_answer(current_question.event, answer.strip())
                            if not valid:
                                error_occurred = True
                                error_msg = "ERROR: " + _error_msg
                                break

                            responses = _get_responses(
                                verified_number.domain, verified_number.owner_id, answer, yield_responses=True
                            )
                            current_question = responses[-1]
                            form_complete = is_form_complete(current_question)

                        # If the form isn't finished yet but we're out of arguments, try to leave each remaining question blank and continue
                        while not form_complete and not error_occurred:
                            responses = _get_responses(
                                verified_number.domain, verified_number.owner_id, "", yield_responses=True
                            )
                            current_question = responses[-1]

                            if current_question.is_error:
                                error_occurred = True
                                error_msg = current_question.text_prompt or "ERROR: Internal server error"

                            if is_form_complete(current_question):
                                form_complete = True
            except Exception:
                logging.exception(
                    "Could not process structured sms for verified number %s, domain %s, keyword %s"
                    % (verified_number._id, verified_number.domain, keyword)
                )
                error_occurred = True
                error_msg = "ERROR: Internal server error"

            if error_occurred:
                send_sms_to_verified_number(verified_number, error_msg)

            if error_occurred or not form_complete:
                session = XFormsSession.get(session._id)
                session.end(False)
                session.save()

            return True

    return False
Example #59
0
 def __init__(self, domain, data_source_type, data_source_id):
     super(FormDataSourceMeta, self).__init__(domain, data_source_type,
                                              data_source_id)
     self.source_form = Form.get_form(self.data_source_id)
     self.source_xform = XForm(self.source_form.source)
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers):
    if reminder.callback_try_count > 0:
        # Handle timeouts
        if handler.submit_partial_forms and (reminder.callback_try_count == len(reminder.current_event.callback_timeout_intervals)):
            # Submit partial form completions
            for session_id in reminder.xforms_session_ids:
                submit_unfinished_form(session_id, handler.include_case_side_effects)
        else:
            # Resend current question
            for session_id in reminder.xforms_session_ids:
                session = XFormsSession.view("smsforms/sessions_by_touchforms_id",
                                             startkey=[session_id],
                                             endkey=[session_id, {}],
                                             include_docs=True).one()
                if session.end_time is None:
                    vn = VerifiedNumber.view("sms/verified_number_by_owner_id",
                                             key=session.connection_id,
                                             include_docs=True).first()
                    if vn is not None:
                        metadata = MessageMetadata(
                            workflow=get_workflow(handler),
                            reminder_id=reminder._id,
                            xforms_session_couch_id=session._id,
                        )
                        resp = current_question(session_id)
                        send_sms_to_verified_number(vn, resp.event.text_prompt, metadata)
        return True
    else:
        reminder.xforms_session_ids = []

        # Get the app, module, and form
        try:
            form_unique_id = reminder.current_event.form_unique_id
            form = Form.get_form(form_unique_id)
            app = form.get_app()
            module = form.get_module()
        except Exception as e:
            raise_error(reminder, ERROR_FORM)
            return False

        # Start a touchforms session for each recipient
        for recipient in recipients:

            verified_number, unverified_number = get_recipient_phone_number(
                reminder, recipient, verified_numbers)

            domain_obj = Domain.get_by_name(reminder.domain, strict=True)
            no_verified_number = verified_number is None
            cant_use_unverified_number = (unverified_number is None or
                not domain_obj.send_to_duplicated_case_numbers or
                form_requires_input(form))
            if no_verified_number and cant_use_unverified_number:
                if len(recipients) == 1:
                    raise_error(reminder, ERROR_NO_VERIFIED_NUMBER)
                    return False
                else:
                    continue

            # Close all currently open sessions
            XFormsSession.close_all_open_sms_sessions(reminder.domain, recipient.get_id)

            # Start the new session
            if isinstance(recipient, CommCareCase) and not handler.force_surveys_to_use_triggered_case:
                case_id = recipient.get_id
            else:
                case_id = reminder.case_id
            session, responses = start_session(reminder.domain, recipient, app, module, form, case_id, case_for_case_submission=handler.force_surveys_to_use_triggered_case)
            session.survey_incentive = handler.survey_incentive
            session.workflow = get_workflow(handler)
            session.reminder_id = reminder._id
            session.save()
            reminder.xforms_session_ids.append(session.session_id)

            # Send out first message
            if len(responses) > 0:
                message = format_message_list(responses)
                metadata = MessageMetadata(
                    workflow=get_workflow(handler),
                    reminder_id=reminder._id,
                    xforms_session_couch_id=session._id,
                )
                if verified_number:
                    result = send_sms_to_verified_number(verified_number, message, metadata)
                else:
                    result = send_sms(reminder.domain, recipient, unverified_number,
                        message, metadata)

                if len(recipients) == 1:
                    return result

        return True