def _test_custom_icon_in_suite(self, form_or_module, locale_id,
                                   custom_icon_locale_method, xml_node):
        """
        :param form_or_module: form or module for which to test
        :param locale_id: text locale id in display block for form or module
        :param custom_icon_locale_method: method to find locale id in app strings for custom icon
        :param xml_node: where to find the xml partial for comparison
        """
        custom_icon = CustomIcon(form="badge",
                                 text={
                                     'en': 'IconText',
                                     'hin': 'चित्र'
                                 })
        form_or_module.custom_icons = [custom_icon]

        custom_icon_block_template = """
            <partial>
                <display>
                    <text>
                        <locale id="{locale_id}"/>
                    </text>
                    <text form="badge">
                        {locale_or_xpath}
                    </text>
                </display>
            </partial>
        """
        custom_icon_locale = custom_icon_locale_method(form_or_module,
                                                       custom_icon.form)
        text_locale_partial = '<locale id="{custom_icon_locale}"/>'.format(
            custom_icon_locale=custom_icon_locale)

        # check for text locale
        custom_icon_block = custom_icon_block_template.format(
            locale_id=locale_id, locale_or_xpath=text_locale_partial)
        self.assertXmlPartialEqual(custom_icon_block, self.app.create_suite(),
                                   xml_node)
        self._assert_app_strings_available(self.app, 'en')

        # check for translation for text locale
        self._assert_valid_media_translation(self.app, 'hin',
                                             custom_icon_locale,
                                             custom_icon.text['hin'])

        # check for default in case of missing translation
        self._assert_valid_media_translation(self.app, 'secret',
                                             custom_icon_locale,
                                             custom_icon.text['en'])

        # check for xpath being set for custom icon
        custom_icon.xpath = "if(1=1, 'a', 'b')"
        custom_icon.text = {}
        form_or_module.custom_icons = [custom_icon]
        custom_icon_block = custom_icon_block_template.format(
            locale_id=locale_id,
            locale_or_xpath='<xpath function="{xpath}"/>'.format(
                xpath=custom_icon.xpath))
        self.assertXmlPartialEqual(custom_icon_block, self.app.create_suite(),
                                   xml_node)
Exemple #2
0
def handle_custom_icon_edits(request, form_or_module, lang):
    if toggles.CUSTOM_ICON_BADGES.enabled(request.domain):
        icon_text_body = request.POST.get("custom_icon_text_body")
        icon_xpath = request.POST.get("custom_icon_xpath")
        icon_form = request.POST.get("custom_icon_form")

        # if there is a request to set custom icon
        if icon_form:
            # validate that only of either text or xpath should be present
            if (icon_text_body and icon_xpath) or (not icon_text_body
                                                   and not icon_xpath):
                return _(
                    "Please enter either text body or xpath for custom icon")

            # a form should have just one custom icon for now
            # so this just adds a new one with params or replaces the existing one with new params
            form_custom_icon = (form_or_module.custom_icon if
                                form_or_module.custom_icon else CustomIcon())
            form_custom_icon.form = icon_form
            form_custom_icon.text[lang] = icon_text_body
            form_custom_icon.xpath = icon_xpath

            form_or_module.custom_icons = [form_custom_icon]

        # if there is a request to unset custom icon
        if not icon_form and form_or_module.custom_icon:
            form_or_module.custom_icons = []
    def _test_custom_icon_in_suite(self, form_or_module, locale_id, custom_icon_locale_method, xml_node):
        """
        :param form_or_module: form or module for which to test
        :param locale_id: text locale id in display block for form or module
        :param custom_icon_locale_method: method to find locale id in app strings for custom icon
        :param xml_node: where to find the xml partial for comparison
        """
        custom_icon = CustomIcon(form="badge", text={'en': 'IconText', 'hin': 'चित्र'})
        form_or_module.custom_icons = [custom_icon]

        custom_icon_block_template = """
            <partial>
                <display>
                    <text>
                        <locale id="{locale_id}"/>
                    </text>
                    <text form="badge">
                        {locale_or_xpath}
                    </text>
                </display>
            </partial>
        """
        custom_icon_locale = custom_icon_locale_method(form_or_module, custom_icon.form)
        text_locale_partial = '<locale id="{custom_icon_locale}"/>'.format(custom_icon_locale=custom_icon_locale)

        # check for text locale
        custom_icon_block = custom_icon_block_template.format(locale_id=locale_id,
                                                              locale_or_xpath=text_locale_partial)
        self.assertXmlPartialEqual(custom_icon_block, self.app.create_suite(), xml_node)
        self._assert_app_strings_available(self.app, 'en')

        # check for translation for text locale
        self._assert_valid_media_translation(self.app, 'hin', custom_icon_locale, custom_icon.text['hin'])

        # check for default in case of missing translation
        self._assert_valid_media_translation(self.app, 'secret', custom_icon_locale, custom_icon.text['en'])

        # check for xpath being set for custom icon
        custom_icon.xpath = "if(1=1, 'a', 'b')"
        custom_icon.text = {}
        form_or_module.custom_icons = [custom_icon]
        custom_icon_block = custom_icon_block_template.format(
            locale_id=locale_id,
            locale_or_xpath='<xpath function="{xpath}"/>'.format(xpath=custom_icon.xpath)
        )
        self.assertXmlPartialEqual(custom_icon_block, self.app.create_suite(), xml_node)
Exemple #4
0
def get_form_view_context_and_template(request, domain, form, langs, current_lang, messages=messages):
    xform_questions = []
    xform = None
    form_errors = []
    xform_validation_errored = False
    xform_validation_missing = False

    try:
        xform = form.wrapped_xform()
    except XFormException as e:
        form_errors.append("Error in form: %s" % e)
    except Exception as e:
        logging.exception(e)
        form_errors.append("Unexpected error in form: %s" % e)

    has_case_error = False
    if xform and xform.exists():
        if xform.already_has_meta():
            messages.warning(
                request,
                "This form has a meta block already! "
                "It may be replaced by CommCare HQ's standard meta block."
            )

        try:
            xform_questions = xform.get_questions(langs, include_triggers=True)
            form.validate_form()
        except etree.XMLSyntaxError as e:
            form_errors.append("Syntax Error: %s" % e)
        except AppEditingError as e:
            form_errors.append("Error in application: %s" % e)
        except XFormValidationError:
            xform_validation_errored = True
            # showing these messages is handled by validate_form_for_build ajax
        except XFormValidationFailed:
            xform_validation_missing = True
            messages.warning(request, _("Unable to validate form due to server error."))
        except XFormException as e:
            form_errors.append("Error in form: %s" % e)
        # any other kind of error should fail hard,
        # but for now there are too many for that to be practical
        except Exception as e:
            if settings.DEBUG:
                raise
            notify_exception(request, 'Unexpected Build Error')
            form_errors.append("Unexpected System Error: %s" % e)
        else:
            # remove upload questions (attachments) until MM Case Properties
            # are released to general public
            is_previewer = toggles.MM_CASE_PROPERTIES.enabled_for_request(request)
            xform_questions = [q for q in xform_questions
                               if q["tag"] != "upload" or is_previewer]

        if not form_errors and not xform_validation_missing and not xform_validation_errored:
            try:
                form_action_errors = form.validate_for_build()
                if not form_action_errors:
                    form.add_stuff_to_xform(xform)
            except CaseError as e:
                has_case_error = True
                messages.error(request, "Error in Case Management: %s" % e)
            except XFormException as e:
                messages.error(request, str(e))
            except Exception as e:
                if settings.DEBUG:
                    raise
                logging.exception(str(e))
                messages.error(request, "Unexpected Error: %s" % e)

    try:
        languages = xform.get_languages()
    except Exception:
        languages = []

    for err in form_errors:
        messages.error(request, err)

    module_case_types = []
    app = form.get_app()
    all_modules = list(app.get_modules())
    for module in all_modules:
        for case_type in module.get_case_types():
            module_case_types.append({
                'id': module.unique_id,
                'module_name': trans(module.name, langs),
                'case_type': case_type,
                'module_type': module.doc_type
            })
    module = form.get_module()

    if not form.unique_id:
        form.get_unique_id()
        app.save()

    allow_usercase = domain_has_privilege(request.domain, privileges.USERCASE)
    valid_index_names = list(DEFAULT_CASE_INDEX_IDENTIFIERS.values())
    if allow_usercase:
        valid_index_names.append(USERCASE_PREFIX[0:-1])     # strip trailing slash

    form_has_schedule = isinstance(form, AdvancedForm) and module.has_schedule

    try:
        case_properties_map = get_all_case_properties(app)
        usercase_properties_map = get_usercase_properties(app)
    except CaseError as e:
        case_properties_map = {}
        usercase_properties_map = {}
        if not has_case_error:
            messages.error(request, "Error in Case Management: %s" % e)

    case_config_options = {
        'caseType': form.get_case_type(),
        'moduleCaseTypes': module_case_types,
        'propertiesMap': case_properties_map,
        'propertyDescriptions': get_case_property_description_dict(domain),
        'questions': xform_questions,
        'reserved_words': load_case_reserved_words(),
        'usercasePropertiesMap': usercase_properties_map,
    }
    context = {
        'nav_form': form,
        'xform_languages': languages,
        'form_errors': form_errors,
        'xform_validation_errored': xform_validation_errored,
        'xform_validation_missing': xform_validation_missing,
        'allow_form_copy': isinstance(form, (Form, AdvancedForm)),
        'allow_form_filtering': not form_has_schedule,
        'uses_form_workflow': form.post_form_workflow == WORKFLOW_FORM,
        'allow_usercase': allow_usercase,
        'is_usercase_in_use': is_usercase_in_use(request.domain),
        'is_module_filter_enabled': app.enable_module_filtering,
        'is_training_module': module.is_training_module,
        'is_allowed_to_be_release_notes_form': form.is_allowed_to_be_release_notes_form,
        'root_requires_same_case': module.root_requires_same_case(),
        'is_case_list_form': form.is_case_list_form,
        'edit_name_url': reverse('edit_form_attr', args=[app.domain, app.id, form.unique_id, 'name']),
        'form_filter_patterns': {
            'case_substring': CASE_XPATH_SUBSTRING_MATCHES,
            'usercase_substring': USERCASE_XPATH_SUBSTRING_MATCHES,
        },
        'custom_instances': [
            {'instanceId': instance.instance_id, 'instancePath': instance.instance_path}
            for instance in form.custom_instances
        ],
        'custom_assertions': [
            {'test': assertion.test, 'text': assertion.text.get(current_lang)}
            for assertion in form.custom_assertions
        ],
        'form_icon': None,
        'session_endpoints_enabled': toggles.SESSION_ENDPOINTS.enabled(domain),
        'module_is_multi_select': module.is_multi_select(),
        'module_loads_registry_case': module_loads_registry_case(module),
    }

    if toggles.CUSTOM_ICON_BADGES.enabled(domain):
        context['form_icon'] = form.custom_icon if form.custom_icon else CustomIcon()

    if toggles.COPY_FORM_TO_APP.enabled_for_request(request):
        context['apps_modules'] = get_apps_modules(domain, app.id, module.unique_id)

    if toggles.FORM_LINK_WORKFLOW.enabled(domain):
        context.update(_get_form_link_context(module, langs))

    if isinstance(form, AdvancedForm):
        def commtrack_programs():
            if app.commtrack_enabled:
                programs = Program.by_domain(app.domain)
                return [{'value': program.get_id, 'label': program.name} for program in programs]
            else:
                return []

        all_programs = [{'value': '', 'label': _('All Programs')}]
        case_config_options.update({
            'commtrack_enabled': app.commtrack_enabled,
            'commtrack_programs': all_programs + commtrack_programs(),
            'module_id': module.unique_id,
            'save_url': reverse("edit_advanced_form_actions", args=[app.domain, app.id, form.unique_id]),
            'arbitrary_datums': form.arbitrary_datums,
        })
        if form.form_type == "shadow_form":
            case_config_options.update({
                'actions': form.extra_actions,
                'isShadowForm': True,
            })
        else:
            case_config_options.update({
                'actions': form.actions,
                'isShadowForm': False,
            })
        if getattr(module, 'has_schedule', False):
            schedule_options = get_schedule_context(form)
            schedule_options.update({
                'phase': schedule_options['schedule_phase'],
                'questions': xform_questions,
                'save_url': reverse("edit_visit_schedule", args=[app.domain, app.id, form.unique_id]),
                'schedule': form.schedule,
            })
            context.update({
                'schedule_options': schedule_options,
            })
    else:
        context.update({
            'show_custom_ref': toggles.APP_BUILDER_CUSTOM_PARENT_REF.enabled_for_request(request),
        })
        case_config_options.update({
            'actions': form.actions,
            'allowUsercase': allow_usercase,
            'save_url': reverse("edit_form_actions", args=[app.domain, app.id, form.unique_id]),
            'valid_index_names': valid_index_names,
        })

    context.update({'case_config_options': case_config_options})
    return "app_manager/form_view.html", context
Exemple #5
0
def view_generic(request,
                 domain,
                 app_id,
                 module_id=None,
                 form_id=None,
                 copy_app_form=None,
                 release_manager=False,
                 module_unique_id=None,
                 form_unique_id=None):
    """
    This is the main view for the app. All other views redirect to here.

    """
    if form_id and not module_id and module_unique_id is None:
        return bail(request, domain, app_id)

    app = get_app(domain, app_id)
    module = form = None

    if module_id:
        try:
            module = app.get_module(module_id)
        except ModuleNotFoundException:
            raise Http404()
        if not module.unique_id:
            module.get_or_create_unique_id()
            app.save()
    elif module_unique_id:
        try:
            module = app.get_module_by_unique_id(module_unique_id)
        except ModuleNotFoundException:
            raise Http404()
        module_id = module.id

    if form_id and module is not None:
        try:
            form = module.get_form(form_id)
        except IndexError:
            raise Http404()
    elif form_unique_id:
        try:
            form = app.get_form(form_unique_id)
        except FormNotFoundException:
            raise Http404()
        form_id = form.id

    if form is not None and module is None:
        # this is the case where only the form_unique_id is given
        module = form.get_module()
        module_id = module.id

    # Application states that should no longer exist
    if app.application_version == APP_V1:
        _assert = soft_assert()
        _assert(False, 'App version 1.0', {'domain': domain, 'app_id': app_id})
        return render(request, "app_manager/no_longer_supported.html", {
            'domain': domain,
            'app': app,
        })
    if not app.vellum_case_management and not app.is_remote_app():
        # Soft assert but then continue rendering; template will contain a user-facing warning
        _assert = soft_assert(['jschweers' + '@' + 'dimagi.com'])
        _assert(False, 'vellum_case_management=False', {
            'domain': domain,
            'app_id': app_id
        })
    if (form is not None
            and "usercase_preload" in getattr(form, "actions", {})
            and form.actions.usercase_preload.preload):
        _assert = soft_assert(['dmiller' + '@' + 'dimagi.com'])
        _assert(
            False, 'User property easy refs + old-style config = bad', {
                'domain': domain,
                'app_id': app_id,
                'module_id': module_id,
                'module_unique_id': module_unique_id,
                'form_id': form_id,
                'form_unique_id': form_unique_id,
            })

    context = get_apps_base_context(request, domain, app)
    if app.copy_of:
        # redirect to "main" app rather than specific build
        return HttpResponseRedirect(
            reverse("view_app", args=[domain, app.copy_of]))

    context.update({
        'module': module,
        'form': form,
    })

    lang = context['lang']
    if not module and hasattr(app, 'translations'):
        context.update({"translations": app.translations.get(lang, {})})

    if not app.is_remote_app():
        context.update({
            'add_ons':
            add_ons.get_dict(request, app, module, form),
            'add_ons_privileges':
            add_ons.get_privileges_dict(request),
            'add_ons_layout':
            add_ons.get_layout(request),
        })

    if form:
        template, form_context = get_form_view_context_and_template(
            request, domain, form, context['langs'], current_lang=lang)
        context.update(form_context)
    elif module:
        template = get_module_template(request.user, module)
        # make sure all modules have unique ids
        app.ensure_module_unique_ids(should_save=True)
        module_context = get_module_view_context(request, app, module, lang)
        context.update(module_context)
    else:
        context.update(get_app_view_context(request, app))

        template = 'app_manager/app_view_settings.html'
        if release_manager:
            template = 'app_manager/app_view_release_manager.html'
        if release_manager:
            context.update(get_releases_context(request, domain, app_id))
        context.update({
            'is_app_settings_page': not release_manager,
        })

    # update multimedia context for forms and modules.
    menu_host = form or module
    if menu_host:
        default_file_name = 'module%s' % module_id
        if form:
            default_file_name = '%s_form%s' % (default_file_name, form_id)

        specific_media = [{
            'menu_refs':
            app.get_menu_media(module,
                               form=form,
                               form_index=form_id,
                               to_language=lang),
            'default_file_name':
            '{name}_{lang}'.format(name=default_file_name, lang=lang),
        }]

        if not form and module and not isinstance(
                module, ReportModule) and module.uses_media():

            def _make_name(suffix):
                return "{default_name}_{suffix}_{lang}".format(
                    default_name=default_file_name,
                    suffix=suffix,
                    lang=lang,
                )

            specific_media.append({
                'menu_refs':
                app.get_case_list_form_media(module, to_language=lang),
                'default_file_name':
                _make_name('case_list_form'),
                'qualifier':
                'case_list_form_',
            })
            specific_media.append({
                'menu_refs':
                app.get_case_list_menu_item_media(module, to_language=lang),
                'default_file_name':
                _make_name('case_list_menu_item'),
                'qualifier':
                'case_list-menu_item_',
            })
            if (toggles.CASE_LIST_LOOKUP.enabled(request.user.username)
                    or toggles.CASE_LIST_LOOKUP.enabled(app.domain)
                    or toggles.BIOMETRIC_INTEGRATION.enabled(app.domain)):
                specific_media.append({
                    'menu_refs':
                    app.get_case_list_lookup_image(module),
                    'default_file_name':
                    '{}_case_list_lookup'.format(default_file_name),
                    'qualifier':
                    'case-list-lookupcase',
                })

                if hasattr(module, 'product_details'):
                    specific_media.append({
                        'menu_refs':
                        app.get_case_list_lookup_image(module, type='product'),
                        'default_file_name':
                        '{}_product_list_lookup'.format(default_file_name),
                        'qualifier':
                        'case-list-lookupproduct',
                    })

        uploaders = {
            'icon':
            MultimediaImageUploadController(
                "hqimage",
                reverse(ProcessImageFileUploadView.urlname,
                        args=[app.domain, app.get_id])),
            'audio':
            MultimediaAudioUploadController(
                "hqaudio",
                reverse(ProcessAudioFileUploadView.urlname,
                        args=[app.domain, app.get_id])),
        }

        multimedia_map = app.multimedia_map
        if form or module:
            multimedia_map = (form or module).get_relevant_multimedia_map(app)
        context.update({
            'multimedia': {
                "object_map":
                app.get_object_map(multimedia_map=multimedia_map),
                'upload_managers': uploaders,
                'upload_managers_js':
                {type: u.js_options
                 for type, u in uploaders.items()},
            }
        })

        context['module_icon'] = None
        if toggles.CUSTOM_ICON_BADGES.enabled(domain):
            context[
                'module_icon'] = module.custom_icon if module.custom_icon else CustomIcon(
                )
        context['nav_menu_media_specifics'] = specific_media

    error = request.GET.get('error', '')

    context.update({
        'error': error,
        'app': app,
    })

    # Pass form for Copy Application to template
    domain_names = {
        d.name
        for d in Domain.active_for_user(request.couch_user)
        if not (is_linked_domain(request.domain) and get_domain_master_link(
            request.domain).master_domain == d.name)
    }
    domain_names.add(request.domain)
    if copy_app_form is None:
        copy_app_form = CopyApplicationForm(domain, app)
        context.update({
            'domain_names': sorted(domain_names),
        })
    linked_domains_enabled = toggles.LINKED_DOMAINS.enabled(domain)
    context.update({
        'copy_app_form': copy_app_form,
        'linked_domains_enabled': linked_domains_enabled,
    })

    context['latest_commcare_version'] = get_commcare_versions(
        request.user)[-1]

    if not is_remote_app(app) and has_privilege(
            request, privileges.COMMCARE_LOGO_UPLOADER):
        uploader_slugs = list(ANDROID_LOGO_PROPERTY_MAPPING.keys())
        from corehq.apps.hqmedia.controller import MultimediaLogoUploadController
        from corehq.apps.hqmedia.views import ProcessLogoFileUploadView
        uploaders = [
            MultimediaLogoUploadController(
                slug,
                reverse(
                    ProcessLogoFileUploadView.urlname,
                    args=[domain, app_id, slug],
                )) for slug in uploader_slugs
        ]
        context.update({
            "sessionid": request.COOKIES.get('sessionid'),
            "uploaders": uploaders,
            "uploaders_js": [u.js_options for u in uploaders],
            "refs": {
                slug: ApplicationMediaReference(
                    app.logo_refs.get(slug, {}).get("path", slug),
                    media_class=CommCareImage,
                ).as_dict()
                for slug in uploader_slugs
            },
            "media_info": {
                slug: app.logo_refs.get(slug)
                for slug in uploader_slugs if app.logo_refs.get(slug)
            },
        })

    context.update({
        'show_live_preview':
        should_show_preview_app(request, app, request.couch_user.username),
        'can_preview_form':
        request.couch_user.has_permission(domain, 'edit_data')
    })

    confirm = request.session.pop('CONFIRM', False)
    context.update({'confirm': confirm})

    response = render(request, template, context)

    set_lang_cookie(response, lang)
    return response