示例#1
0
        def get_commands():
            for form in module.get_suite_forms():
                command = Command(id=id_strings.form_command(form, module))

                if form.requires_case():
                    form_datums = self.entries_helper.get_datums_meta_for_form_generic(form, module)
                    var_name = next(
                        meta.datum.id for meta in reversed(form_datums) if meta.action and meta.requires_selection
                    )
                    case = CaseIDXPath(session_var(var_name)).case()
                else:
                    case = None

                if (
                    getattr(form, "form_filter", None)
                    and not module.put_in_root
                    and (module.all_forms_require_a_case() or is_usercase_in_use(self.app.domain))
                ):
                    fixture_xpath = (
                        session_var(id_strings.fixture_session_var(module)) if module.fixture_select.active else None
                    )
                    command.relevant = interpolate_xpath(form.form_filter, case, fixture_xpath)

                if getattr(module, "has_schedule", False) and module.all_forms_require_a_case():
                    # If there is a schedule and another filter condition, disregard it...
                    # Other forms of filtering are disabled in the UI

                    schedule_filter_condition = MenuContributor._schedule_filter_conditions(form, module, case)
                    if schedule_filter_condition is not None:
                        command.relevant = schedule_filter_condition

                yield command

            if hasattr(module, "case_list") and module.case_list.show:
                yield Command(id=id_strings.case_list_command(module))
示例#2
0
 def test_interpolate_xpath(self):
     replacements = {
         'case': "<casedb stuff>",
         'user': UserCaseXPath().case(),
         'session': "instance('commcaresession')/session",
     }
     cases = [
         ('./lmp < 570.5', '{case}/lmp < 570.5'),
         ('#case/lmp < 570.5', '{case}/lmp < 570.5'),
         ('stuff ./lmp < 570.', 'stuff {case}/lmp < 570.'),
         ('stuff #case/lmp < 570.', 'stuff {case}/lmp < 570.'),
         ('.53 < hello.', '.53 < hello{case}'),
         ('.53 < hello#case', '.53 < hello{case}'),
         ('#session/data/username', '{session}/data/username'),
         ('"jack" = #session/username', '"jack" = {session}/username'),
         ('./@case_id = #session/userid', '{case}/@case_id = {session}/userid'),
         ('#case/@case_id = #user/@case_id', '{case}/@case_id = {user}/@case_id'),
         ('#host/foo = 42', "instance('casedb')/casedb/case[@case_id={case}/index/host]/foo = 42"),
         ("'ham' = #parent/spam", "'ham' = instance('casedb')/casedb/case[@case_id={case}/index/parent]/spam"),
     ]
     for case in cases:
         self.assertEqual(
             interpolate_xpath(case[0], replacements['case']),
             case[1].format(**replacements)
         )
示例#3
0
 def get_filter_xpath(module, delegation=False):
     filter = module.case_details.short.filter
     if filter:
         xpath = "[%s]" % interpolate_xpath(filter)
     else:
         xpath = ""
     if delegation:
         xpath += "[index/parent/@case_type = '%s']" % module.case_type
         xpath += "[start_date = '' or double(date(start_date)) <= double(now())]"
     return xpath
示例#4
0
 def get_filter_xpath(module, delegation=False):
     filter = module.case_details.short.filter
     if filter:
         xpath = '[%s]' % interpolate_xpath(filter)
     else:
         xpath = ''
     if delegation:
         xpath += "[index/parent/@case_type = '%s']" % module.case_type
         xpath += "[start_date = '' or double(date(start_date)) <= double(now())]"
     return xpath
示例#5
0
        def get_commands(excluded_form_ids):
            @memoized
            def module_uses_case():
                return module.all_forms_require_a_case()

            @memoized
            def domain_uses_usercase():
                return is_usercase_in_use(self.app.domain)

            for form in module.get_suite_forms():
                if form.unique_id in excluded_form_ids:
                    continue

                command = Command(id=id_strings.form_command(form, module))

                if form.requires_case():
                    form_datums = self.entries_helper.get_datums_meta_for_form_generic(form, module)
                    var_name = next(
                        meta.datum.id for meta in reversed(form_datums)
                        if meta.action and meta.requires_selection
                    )
                    case = CaseIDXPath(session_var(var_name)).case()
                else:
                    case = None

                if getattr(form, 'form_filter', None):
                    fixture_xpath = (
                        session_var(id_strings.fixture_session_var(module)) if module.fixture_select.active
                        else None
                    )
                    interpolated_xpath = interpolate_xpath(form.form_filter, case, fixture_xpath,
                        module=module, form=form)

                    if xpath_references_case(interpolated_xpath) and \
                            (not module_uses_case() or
                            module.put_in_root and not module.root_requires_same_case()):
                        raise CaseXPathValidationError(module=module, form=form)

                    if xpath_references_user_case(interpolated_xpath) and not domain_uses_usercase():
                        raise UserCaseXPathValidationError(module=module, form=form)

                    command.relevant = interpolated_xpath

                if getattr(module, 'has_schedule', False) and module.all_forms_require_a_case():
                    # If there is a schedule and another filter condition, disregard it...
                    # Other forms of filtering are disabled in the UI

                    schedule_filter_condition = MenuContributor._schedule_filter_conditions(form, module, case)
                    if schedule_filter_condition is not None:
                        command.relevant = schedule_filter_condition

                yield command

            if hasattr(module, 'case_list') and module.case_list.show:
                yield Command(id=id_strings.case_list_command(module))
示例#6
0
 def validate_details_for_build(self):
     errors = []
     for sort_element in self.module.detail_sort_elements:
         try:
             self._validate_detail_screen_field(sort_element.field)
         except ValueError:
             errors.append({
                 'type': 'invalid sort field',
                 'field': sort_element.field,
                 'module': self.get_module_info(),
             })
     if self.module.case_list_filter:
         try:
             # test filter is valid, while allowing for advanced user hacks like "foo = 1][bar = 2"
             case_list_filter = interpolate_xpath(
                 'dummy[' + self.module.case_list_filter + ']')
             etree.XPath(case_list_filter)
         except (etree.XPathSyntaxError, CaseXPathValidationError):
             errors.append({
                 'type': 'invalid filter xpath',
                 'module': self.get_module_info(),
                 'filter': self.module.case_list_filter,
             })
     for detail in [
             self.module.case_details.short, self.module.case_details.long
     ]:
         if detail.use_case_tiles:
             if not detail.display == "short":
                 errors.append({
                     'type':
                     "invalid tile configuration",
                     'module':
                     self.get_module_info(),
                     'reason':
                     _('Case tiles may only be used for the case list (not the case details).'
                       )
                 })
             col_by_tile_field = {
                 c.case_tile_field: c
                 for c in detail.columns
             }
             for field in [
                     "header", "top_left", "sex", "bottom_left", "date"
             ]:
                 if field not in col_by_tile_field:
                     errors.append({
                         'type':
                         "invalid tile configuration",
                         'module':
                         self.get_module_info(),
                         'reason':
                         _('A case property must be assigned to the "{}" tile field.'
                           .format(field))
                     })
     return errors
示例#7
0
    def build_query_prompts(self):
        prompts = []
        for prop in self.module.search_config.properties:
            text = Text(locale_id=id_strings.search_property_locale(
                self.module, prop.name))
            if prop.hint:
                display = Display(
                    text=text,
                    hint=Hint(text=Text(
                        locale_id=id_strings.search_property_hint_locale(
                            self.module, prop.name))))
            else:
                display = Display(text=text)

            kwargs = {'key': prop.name, 'display': display}
            if not prop.appearance or prop.itemset.nodeset:
                kwargs['receive'] = prop.receiver_expression
            if prop.hidden:
                kwargs['hidden'] = prop.hidden
            if prop.appearance and self.app.enable_search_prompt_appearance:
                if prop.appearance == 'address':
                    kwargs['input_'] = prop.appearance
                else:
                    kwargs['appearance'] = prop.appearance
            if prop.input_:
                kwargs['input_'] = prop.input_
            if prop.default_value and self.app.enable_default_value_expression:
                kwargs['default_value'] = prop.default_value
            if prop.itemset.nodeset:
                kwargs['itemset'] = Itemset(
                    nodeset=prop.itemset.nodeset,
                    label_ref=prop.itemset.label,
                    value_ref=prop.itemset.value,
                    sort_ref=prop.itemset.sort,
                )
            if prop.allow_blank_value:
                kwargs['allow_blank_value'] = prop.allow_blank_value
            if prop.exclude:
                kwargs['exclude'] = "true()"
            if prop.required:
                kwargs['required'] = interpolate_xpath(prop.required)
            prompts.append(QueryPrompt(**kwargs))
        return prompts
示例#8
0
    def _get_detail_tab_nodeset(self, module, detail, tab):
        if not tab.has_nodeset:
            return None

        if tab.nodeset:
            return tab.nodeset

        if tab.nodeset_case_type:
            nodeset = CaseTypeXpath(tab.nodeset_case_type)
            nodeset = nodeset.case(
                instance_name=detail.get_instance_name(module))
            nodeset = nodeset.select(
                CaseXPath().parent_id(),
                CaseXPath("current()").property("@case_id"))
            nodeset = nodeset.select("@status", "open")
            if tab.nodeset_filter:
                nodeset = nodeset.select_raw(
                    interpolate_xpath(tab.nodeset_filter))
            return nodeset

        return None
示例#9
0
 def validate_details_for_build(self):
     errors = []
     for sort_element in self.module.detail_sort_elements:
         try:
             self._validate_detail_screen_field(sort_element.field)
         except ValueError:
             errors.append({
                 'type': 'invalid sort field',
                 'field': sort_element.field,
                 'module': self.get_module_info(),
             })
     if self.module.case_list_filter:
         try:
             # test filter is valid, while allowing for advanced user hacks like "foo = 1][bar = 2"
             case_list_filter = interpolate_xpath('dummy[' + self.module.case_list_filter + ']')
             etree.XPath(case_list_filter)
         except (etree.XPathSyntaxError, CaseXPathValidationError):
             errors.append({
                 'type': 'invalid filter xpath',
                 'module': self.get_module_info(),
                 'filter': self.module.case_list_filter,
             })
     for detail in [self.module.case_details.short, self.module.case_details.long]:
         if detail.use_case_tiles:
             if not detail.display == "short":
                 errors.append({
                     'type': "invalid tile configuration",
                     'module': self.get_module_info(),
                     'reason': _('Case tiles may only be used for the case list (not the case details).')
                 })
             col_by_tile_field = {c.case_tile_field: c for c in detail.columns}
             for field in ["header", "top_left", "sex", "bottom_left", "date"]:
                 if field not in col_by_tile_field:
                     errors.append({
                         'type': "invalid tile configuration",
                         'module': self.get_module_info(),
                         'reason': _('A case property must be assigned to the "{}" tile field.'.format(field))
                     })
     return errors
示例#10
0
 def test_interpolate_xpath_error(self):
     for case in ('./lmp < 570.5', '#case/lmp < 570.5'):
         with self.assertRaises(CaseXPathValidationError):
             interpolate_xpath(case, None),
示例#11
0
    def get_module_contributions(self, module):
        def get_commands():
            for form in module.get_suite_forms():
                command = Command(id=id_strings.form_command(form, module))

                if form.requires_case():
                    form_datums = self.entries_helper.get_datums_meta_for_form_generic(form, module)
                    var_name = next(
                        meta.datum.id for meta in reversed(form_datums)
                        if meta.action and meta.requires_selection
                    )
                    case = CaseIDXPath(session_var(var_name)).case()
                else:
                    case = None

                if (
                    getattr(form, 'form_filter', None) and
                    not module.put_in_root and
                    (module.all_forms_require_a_case() or is_usercase_in_use(self.app.domain))
                ):
                    fixture_xpath = (
                        session_var(id_strings.fixture_session_var(module)) if module.fixture_select.active
                        else None
                    )
                    command.relevant = interpolate_xpath(form.form_filter, case, fixture_xpath)

                if getattr(module, 'has_schedule', False) and module.all_forms_require_a_case():
                    # If there is a schedule and another filter condition, disregard it...
                    # Other forms of filtering are disabled in the UI

                    schedule_filter_condition = MenuContributor._schedule_filter_conditions(form, module, case)
                    if schedule_filter_condition is not None:
                        command.relevant = schedule_filter_condition

                yield command

            if hasattr(module, 'case_list') and module.case_list.show:
                yield Command(id=id_strings.case_list_command(module))

        supports_module_filter = (
            self.app.domain and MODULE_FILTER.enabled(self.app.domain) and
            self.app.enable_module_filtering and getattr(module, 'module_filter', None)
        )

        menus = []
        if hasattr(module, 'get_menus'):
            for menu in module.get_menus(supports_module_filter=supports_module_filter):
                menus.append(menu)
        elif module.module_type != 'careplan':
            id_modules = [module]
            root_modules = []

            shadow_modules = [m for m in self.app.get_modules()
                              if m.doc_type == "ShadowModule" and m.source_module_id]
            put_in_root = getattr(module, 'put_in_root', False)
            if not put_in_root and getattr(module, 'root_module', False):
                root_modules.append(module.root_module)
                for shadow in shadow_modules:
                    if module.root_module.unique_id == shadow.source_module_id:
                        root_modules.append(shadow)
            else:
                root_modules.append(None)
                if put_in_root and getattr(module, 'root_module', False):
                    for shadow in shadow_modules:
                        if module.root_module.unique_id == shadow.source_module_id:
                            id_modules.append(shadow)

            for id_module in id_modules:
                for root_module in root_modules:
                    menu_kwargs = {}
                    suffix = ""
                    if root_module:
                        menu_kwargs.update({'root': id_strings.menu_id(root_module)})
                        suffix = id_strings.menu_id(root_module) if root_module.doc_type == 'ShadowModule' else ""
                    menu_kwargs.update({'id': id_strings.menu_id(id_module, suffix)})

                    if supports_module_filter:
                        menu_kwargs['relevant'] = interpolate_xpath(module.module_filter)

                    if self.app.enable_localized_menu_media:
                        menu_kwargs.update({
                            'menu_locale_id': id_strings.module_locale(module),
                            'media_image': bool(len(module.all_image_paths())),
                            'media_audio': bool(len(module.all_audio_paths())),
                            'image_locale_id': id_strings.module_icon_locale(module),
                            'audio_locale_id': id_strings.module_audio_locale(module),
                        })
                        menu = LocalizedMenu(**menu_kwargs)
                    else:
                        menu_kwargs.update({
                            'locale_id': id_strings.module_locale(module),
                            'media_image': module.default_media_image,
                            'media_audio': module.default_media_audio,
                        })
                        menu = Menu(**menu_kwargs)

                    menu.commands.extend(get_commands())

                    menus.append(menu)

        if self.app.use_grid_menus:
            self._give_root_menus_grid_style(menus)

        return menus
示例#12
0
class MenuContributor(SuiteContributorByModule):
    def get_module_contributions(self, module):
        def get_commands(excluded_form_ids):
            @memoized
            def module_uses_case():
                return module.all_forms_require_a_case()

            @memoized
            def domain_uses_usercase():
                return is_usercase_in_use(self.app.domain)

            for form in module.get_suite_forms():
                if form.unique_id in excluded_form_ids:
                    continue

                command = Command(id=id_strings.form_command(form, module))

                if form.requires_case():
                    form_datums = self.entries_helper.get_datums_meta_for_form_generic(
                        form, module)
                    var_name = next(meta.datum.id
                                    for meta in reversed(form_datums)
                                    if meta.action and meta.requires_selection)
                    case = CaseIDXPath(session_var(var_name)).case()
                else:
                    case = None

                if getattr(form, 'form_filter', None):
                    fixture_xpath = (session_var(
                        id_strings.fixture_session_var(module))
                                     if module.fixture_select.active else None)
                    interpolated_xpath = interpolate_xpath(form.form_filter,
                                                           case,
                                                           fixture_xpath,
                                                           module=module,
                                                           form=form)

                    if xpath_references_case(interpolated_xpath) and \
                            (not module_uses_case() or
                            module.put_in_root and not module.root_requires_same_case()):
                        raise CaseXPathValidationError(module=module,
                                                       form=form)

                    if xpath_references_user_case(
                            interpolated_xpath) and not domain_uses_usercase():
                        raise UserCaseXPathValidationError(module=module,
                                                           form=form)

                    command.relevant = interpolated_xpath

                if getattr(module, 'has_schedule',
                           False) and module.all_forms_require_a_case():
                    # If there is a schedule and another filter condition, disregard it...
                    # Other forms of filtering are disabled in the UI

                    schedule_filter_condition = MenuContributor._schedule_filter_conditions(
                        form, module, case)
                    if schedule_filter_condition is not None:
                        command.relevant = schedule_filter_condition

                yield command

            if hasattr(module, 'case_list') and module.case_list.show:
                yield Command(id=id_strings.case_list_command(module))

        supports_module_filter = self.app.enable_module_filtering and getattr(
            module, 'module_filter', None)

        menus = []
        if hasattr(module, 'get_menus'):
            for menu in module.get_menus(
                    supports_module_filter=supports_module_filter):
                menus.append(menu)
        else:
            from corehq.apps.app_manager.models import ShadowModule
            id_modules = [module]
            root_modules = []

            shadow_modules = [
                m for m in self.app.get_modules()
                if isinstance(m, ShadowModule) and m.source_module_id
            ]
            put_in_root = getattr(module, 'put_in_root', False)
            if not put_in_root and getattr(module, 'root_module', False):
                root_modules.append(module.root_module)
                for shadow in shadow_modules:
                    if module.root_module.unique_id == shadow.source_module_id:
                        root_modules.append(shadow)
            else:
                root_modules.append(None)
                if put_in_root and getattr(module, 'root_module', False):
                    for shadow in shadow_modules:
                        if module.root_module.unique_id == shadow.source_module_id:
                            id_modules.append(shadow)

            for id_module in id_modules:
                for root_module in root_modules:
                    menu_kwargs = {}
                    suffix = ""
                    if root_module:
                        menu_kwargs.update(
                            {'root': id_strings.menu_id(root_module)})
                        suffix = id_strings.menu_id(root_module) if isinstance(
                            root_module, ShadowModule) else ""
                    menu_kwargs.update(
                        {'id': id_strings.menu_id(id_module, suffix)})

                    if supports_module_filter:
                        menu_kwargs['relevant'] = interpolate_xpath(
                            module.module_filter)

                    if self.app.enable_localized_menu_media:
                        module_custom_icon = module.custom_icon
                        menu_kwargs.update({
                            'menu_locale_id':
                            id_strings.module_locale(module),
                            'media_image':
                            bool(len(module.all_image_paths())),
                            'media_audio':
                            bool(len(module.all_audio_paths())),
                            'image_locale_id':
                            id_strings.module_icon_locale(module),
                            'audio_locale_id':
                            id_strings.module_audio_locale(module),
                            'custom_icon_locale_id':
                            (id_strings.module_custom_icon_locale(
                                module, module_custom_icon.form)
                             if module_custom_icon
                             and not module_custom_icon.xpath else None),
                            'custom_icon_form': (module_custom_icon.form if
                                                 module_custom_icon else None),
                            'custom_icon_xpath':
                            (module_custom_icon.xpath if module_custom_icon
                             and module_custom_icon.xpath else None),
                        })
                        menu = LocalizedMenu(**menu_kwargs)
                    else:
                        menu_kwargs.update({
                            'locale_id':
                            id_strings.module_locale(module),
                            'media_image':
                            module.default_media_image,
                            'media_audio':
                            module.default_media_audio,
                        })
                        menu = Menu(**menu_kwargs)

                    excluded_form_ids = []
                    if root_module and isinstance(root_module, ShadowModule):
                        excluded_form_ids = root_module.excluded_form_ids
                    if id_module and isinstance(id_module, ShadowModule):
                        excluded_form_ids = id_module.excluded_form_ids
                    menu.commands.extend(get_commands(excluded_form_ids))

                    if len(menu.commands):
                        menus.append(menu)

        if self.app.grid_display_for_all_modules() or \
                self.app.grid_display_for_some_modules() and module.grid_display_style():
            self._give_non_root_menus_grid_style(menus)
        if self.app.use_grid_menus:
            self._give_root_menu_grid_style(menus)

        return menus
示例#13
0
    def _generate_menu(self, module, root_module, training_menu, id_module):
        # In general, `id_module` and `module` will be the same thing.
        # In the case of v1 shadow menus, `id_module` is either the current module or one of that module's shadows
        # For more information, see the note in `_generate_v1_shadow_menus`.
        from corehq.apps.app_manager.models import ShadowModule
        menu_kwargs = {}
        suffix = ""
        if id_module.is_training_module:
            menu_kwargs.update({'root': 'training-root'})
        elif root_module:
            menu_kwargs.update({'root': id_strings.menu_id(root_module)})
            suffix = id_strings.menu_id(root_module) if isinstance(
                root_module, ShadowModule) else ""
        menu_kwargs.update({'id': id_strings.menu_id(id_module, suffix)})

        # Determine relevancy
        if self.app.enable_module_filtering:
            relevancy = id_module.module_filter
            # If module has a parent, incorporate the parent's relevancy.
            # This is only necessary when the child uses display only forms.
            if id_module.put_in_root and id_module.root_module and id_module.root_module.module_filter:
                if relevancy:
                    relevancy = str(
                        XPath.and_(
                            XPath(relevancy).paren(force=True),
                            XPath(id_module.root_module.module_filter).paren(
                                force=True)))
                else:
                    relevancy = id_module.root_module.module_filter
            if relevancy:
                menu_kwargs['relevant'] = interpolate_xpath(relevancy)

        if self.app.enable_localized_menu_media:
            module_custom_icon = module.custom_icon
            menu_kwargs.update({
                'menu_locale_id':
                get_module_locale_id(module),
                'media_image':
                module.uses_image(build_profile_id=self.build_profile_id),
                'media_audio':
                module.uses_audio(build_profile_id=self.build_profile_id),
                'image_locale_id':
                id_strings.module_icon_locale(module),
                'audio_locale_id':
                id_strings.module_audio_locale(module),
                'custom_icon_locale_id':
                (id_strings.module_custom_icon_locale(
                    module, module_custom_icon.form) if module_custom_icon
                 and not module_custom_icon.xpath else None),
                'custom_icon_form':
                (module_custom_icon.form if module_custom_icon else None),
                'custom_icon_xpath':
                (module_custom_icon.xpath
                 if module_custom_icon and module_custom_icon.xpath else None),
            })
            menu = LocalizedMenu(**menu_kwargs)
        else:
            menu_kwargs.update({
                'media_image': module.default_media_image,
                'media_audio': module.default_media_audio,
                'locale_id': get_module_locale_id(module),
            })
            menu = Menu(**menu_kwargs)

        excluded_form_ids = []
        if root_module and isinstance(root_module, ShadowModule):
            excluded_form_ids = root_module.excluded_form_ids
        if id_module and isinstance(id_module, ShadowModule):
            excluded_form_ids = id_module.excluded_form_ids

        commands = self._get_commands(excluded_form_ids, module)
        if module.is_training_module and module.put_in_root and training_menu:
            training_menu.commands.extend(commands)
        else:
            menu.commands.extend(commands)
        return menu
示例#14
0
class MenuContributor(SuiteContributorByModule):

    def get_module_contributions(self, module, training_menu):
        def get_commands(excluded_form_ids):
            @memoized
            def module_uses_case():
                return module.all_forms_require_a_case()

            @memoized
            def domain_uses_usercase():
                return is_usercase_in_use(self.app.domain)

            for form in module.get_suite_forms():
                if form.unique_id in excluded_form_ids:
                    continue

                command = Command(id=id_strings.form_command(form, module))

                if form.requires_case():
                    form_datums = self.entries_helper.get_datums_meta_for_form_generic(form)
                    var_name = next(
                        meta.datum.id for meta in reversed(form_datums)
                        if meta.action and meta.requires_selection
                    )
                    case = CaseIDXPath(session_var(var_name)).case()
                else:
                    case = None

                if getattr(form, 'form_filter', None):
                    fixture_xpath = (
                        session_var(id_strings.fixture_session_var(module)) if module.fixture_select.active
                        else None
                    )
                    interpolated_xpath = interpolate_xpath(form.form_filter, case, fixture_xpath,
                        module=module, form=form)

                    if xpath_references_case(interpolated_xpath) and \
                            (not module_uses_case() or
                            module.put_in_root and not module.root_requires_same_case()):
                        raise CaseXPathValidationError(module=module, form=form)

                    if xpath_references_user_case(interpolated_xpath) and not domain_uses_usercase():
                        raise UserCaseXPathValidationError(module=module, form=form)

                    command.relevant = interpolated_xpath

                if getattr(module, 'has_schedule', False) and module.all_forms_require_a_case():
                    # If there is a schedule and another filter condition, disregard it...
                    # Other forms of filtering are disabled in the UI

                    schedule_filter_condition = MenuContributor._schedule_filter_conditions(form, module, case)
                    if schedule_filter_condition is not None:
                        command.relevant = schedule_filter_condition

                yield command

            if hasattr(module, 'case_list') and module.case_list.show:
                yield Command(id=id_strings.case_list_command(module))

        menus = []
        if hasattr(module, 'get_menus'):
            for menu in module.get_menus(build_profile_id=self.build_profile_id):
                menus.append(menu)
        else:
            from corehq.apps.app_manager.models import ShadowModule
            id_modules = [module]       # the current module and all of its shadows
            root_modules = []           # the current module's parent and all of that parent's shadows

            shadow_modules = [m for m in self.app.get_modules()
                              if isinstance(m, ShadowModule) and m.source_module_id]
            if not module.put_in_root and module.root_module:
                root_modules.append(module.root_module)
                for shadow in shadow_modules:
                    if module.root_module.unique_id == shadow.source_module_id:
                        root_modules.append(shadow)
            else:
                root_modules.append(None)
                if module.put_in_root and module.root_module:
                    for shadow in shadow_modules:
                        if module.root_module.unique_id == shadow.source_module_id:
                            id_modules.append(shadow)

            for id_module in id_modules:
                for root_module in root_modules:
                    menu_kwargs = {}
                    suffix = ""
                    if id_module.is_training_module:
                        menu_kwargs.update({'root': 'training-root'})
                    elif root_module:
                        menu_kwargs.update({'root': id_strings.menu_id(root_module)})
                        suffix = id_strings.menu_id(root_module) if isinstance(root_module, ShadowModule) else ""
                    menu_kwargs.update({'id': id_strings.menu_id(id_module, suffix)})

                    # Determine relevancy
                    if self.app.enable_module_filtering:
                        relevancy = id_module.module_filter
                        # If module has a parent, incorporate the parent's relevancy.
                        # This is only necessary when the child uses display only forms.
                        if id_module.put_in_root and id_module.root_module and id_module.root_module.module_filter:
                            if relevancy:
                                relevancy = str(XPath.and_(XPath(relevancy).paren(force=True),
                                    XPath(id_module.root_module.module_filter).paren(force=True)))
                            else:
                                relevancy = id_module.root_module.module_filter
                        if relevancy:
                            menu_kwargs['relevant'] = interpolate_xpath(relevancy)

                    if self.app.enable_localized_menu_media:
                        module_custom_icon = module.custom_icon
                        menu_kwargs.update({
                            'menu_locale_id': get_module_locale_id(module),
                            'menu_enum_text': get_module_enum_text(module),
                            'media_image': module.uses_image(build_profile_id=self.build_profile_id),
                            'media_audio': module.uses_audio(build_profile_id=self.build_profile_id),
                            'image_locale_id': id_strings.module_icon_locale(module),
                            'audio_locale_id': id_strings.module_audio_locale(module),
                            'custom_icon_locale_id': (
                                id_strings.module_custom_icon_locale(module, module_custom_icon.form)
                                if module_custom_icon and not module_custom_icon.xpath else None),
                            'custom_icon_form': (module_custom_icon.form if module_custom_icon else None),
                            'custom_icon_xpath': (module_custom_icon.xpath
                                                  if module_custom_icon and module_custom_icon.xpath else None),
                        })
                        menu = LocalizedMenu(**menu_kwargs)
                    else:
                        menu_kwargs.update({
                            'media_image': module.default_media_image,
                            'media_audio': module.default_media_audio,
                            'locale_id': get_module_locale_id(module),
                            'enum_text': get_module_enum_text(module),
                        })
                        menu = Menu(**menu_kwargs)

                    excluded_form_ids = []
                    if root_module and isinstance(root_module, ShadowModule):
                        excluded_form_ids = root_module.excluded_form_ids
                    if id_module and isinstance(id_module, ShadowModule):
                        excluded_form_ids = id_module.excluded_form_ids

                    commands = get_commands(excluded_form_ids)
                    if module.is_training_module and module.put_in_root and training_menu:
                        training_menu.commands.extend(commands)
                    else:
                        menu.commands.extend(commands)

                    if len(menu.commands):
                        menus.append(menu)

        if self.app.grid_display_for_all_modules() or \
                self.app.grid_display_for_some_modules() and module.grid_display_style():
            self._give_non_root_menus_grid_style(menus)
        if self.app.use_grid_menus:
            self._give_root_menu_grid_style(menus)

        return menus
示例#15
0
    def get_module_contributions(self, module):
        def get_commands(excluded_form_ids):
            @memoized
            def module_uses_case():
                return module.all_forms_require_a_case()

            @memoized
            def domain_uses_usercase():
                return is_usercase_in_use(self.app.domain)

            for form in module.get_suite_forms():
                if form.unique_id in excluded_form_ids:
                    continue

                command = Command(id=id_strings.form_command(form, module))

                if form.requires_case():
                    form_datums = self.entries_helper.get_datums_meta_for_form_generic(form, module)
                    var_name = next(
                        meta.datum.id for meta in reversed(form_datums)
                        if meta.action and meta.requires_selection
                    )
                    case = CaseIDXPath(session_var(var_name)).case()
                else:
                    case = None

                if getattr(form, 'form_filter', None):
                    fixture_xpath = (
                        session_var(id_strings.fixture_session_var(module)) if module.fixture_select.active
                        else None
                    )
                    interpolated_xpath = interpolate_xpath(form.form_filter, case, fixture_xpath,
                        module=module, form=form)

                    if xpath_references_case(interpolated_xpath) and \
                            (not module_uses_case() or module.put_in_root):
                        raise CaseXPathValidationError(module=module, form=form)

                    if xpath_references_user_case(interpolated_xpath) and not domain_uses_usercase():
                        raise UserCaseXPathValidationError(module=module, form=form)

                    command.relevant = interpolated_xpath

                if getattr(module, 'has_schedule', False) and module.all_forms_require_a_case():
                    # If there is a schedule and another filter condition, disregard it...
                    # Other forms of filtering are disabled in the UI

                    schedule_filter_condition = MenuContributor._schedule_filter_conditions(form, module, case)
                    if schedule_filter_condition is not None:
                        command.relevant = schedule_filter_condition

                yield command

            if hasattr(module, 'case_list') and module.case_list.show:
                yield Command(id=id_strings.case_list_command(module))

        supports_module_filter = self.app.enable_module_filtering and getattr(module, 'module_filter', None)

        menus = []
        if hasattr(module, 'get_menus'):
            for menu in module.get_menus(supports_module_filter=supports_module_filter):
                menus.append(menu)
        elif module.module_type != 'careplan':
            from corehq.apps.app_manager.models import ShadowModule
            id_modules = [module]
            root_modules = []

            shadow_modules = [m for m in self.app.get_modules()
                              if isinstance(m, ShadowModule) and m.source_module_id]
            put_in_root = getattr(module, 'put_in_root', False)
            if not put_in_root and getattr(module, 'root_module', False):
                root_modules.append(module.root_module)
                for shadow in shadow_modules:
                    if module.root_module.unique_id == shadow.source_module_id:
                        root_modules.append(shadow)
            else:
                root_modules.append(None)
                if put_in_root and getattr(module, 'root_module', False):
                    for shadow in shadow_modules:
                        if module.root_module.unique_id == shadow.source_module_id:
                            id_modules.append(shadow)

            for id_module in id_modules:
                for root_module in root_modules:
                    menu_kwargs = {}
                    suffix = ""
                    if root_module:
                        menu_kwargs.update({'root': id_strings.menu_id(root_module)})
                        suffix = id_strings.menu_id(root_module) if isinstance(root_module, ShadowModule) else ""
                    menu_kwargs.update({'id': id_strings.menu_id(id_module, suffix)})

                    if supports_module_filter:
                        menu_kwargs['relevant'] = interpolate_xpath(module.module_filter)

                    if self.app.enable_localized_menu_media:
                        menu_kwargs.update({
                            'menu_locale_id': id_strings.module_locale(module),
                            'media_image': bool(len(module.all_image_paths())),
                            'media_audio': bool(len(module.all_audio_paths())),
                            'image_locale_id': id_strings.module_icon_locale(module),
                            'audio_locale_id': id_strings.module_audio_locale(module),
                        })
                        menu = LocalizedMenu(**menu_kwargs)
                    else:
                        menu_kwargs.update({
                            'locale_id': id_strings.module_locale(module),
                            'media_image': module.default_media_image,
                            'media_audio': module.default_media_audio,
                        })
                        menu = Menu(**menu_kwargs)

                    excluded_form_ids = []
                    if root_module and isinstance(root_module, ShadowModule):
                        excluded_form_ids = root_module.excluded_form_ids
                    if id_module and isinstance(id_module, ShadowModule):
                        excluded_form_ids = id_module.excluded_form_ids
                    menu.commands.extend(get_commands(excluded_form_ids))

                    if len(menu.commands):
                        menus.append(menu)

        if self.app.grid_display_for_all_modules() or \
                self.app.grid_display_for_some_modules() and module.grid_display_style():
            self._give_non_root_menus_grid_style(menus)
        if self.app.grid_menu_toggle_enabled() and self.app.use_grid_menus:
            self._give_root_menu_grid_style(menus)

        return menus
示例#16
0
    def check_actions(self):
        errors = []

        from corehq.apps.app_manager.models import AdvancedOpenCaseAction, LoadUpdateAction

        case_tags = list(self.form.actions.get_case_tags())
        for action in self.form.actions.get_subcase_actions():
            for case_index in action.case_indices:
                if case_index.tag not in case_tags:
                    errors.append({'type': 'missing parent tag', 'case_tag': case_index.tag})
                if case_index.relationship == 'question' and not case_index.relationship_question:
                    errors.append({'type': 'missing relationship question', 'case_tag': case_index.tag})

            if isinstance(action, AdvancedOpenCaseAction):
                if not action.name_path:
                    errors.append({'type': 'case_name required', 'case_tag': action.case_tag})

                for case_index in action.case_indices:
                    meta = self.form.actions.actions_meta_by_tag.get(case_index.tag)
                    if meta and meta['type'] == 'open' and meta['action'].repeat_context:
                        if (
                            not action.repeat_context or
                            not action.repeat_context.startswith(meta['action'].repeat_context)
                        ):
                            errors.append({'type': 'subcase repeat context',
                                           'case_tag': action.case_tag,
                                           'parent_tag': case_index.tag})

            errors.extend(self.check_case_properties(
                subcase_names=action.get_property_names(),
                case_tag=action.case_tag
            ))

        for action in self.form.actions.get_all_actions():
            if not action.case_type and (not isinstance(action, LoadUpdateAction) or not action.auto_select):
                errors.append({'type': "no case type in action", 'case_tag': action.case_tag})

            if isinstance(action, LoadUpdateAction) and action.auto_select:
                mode = action.auto_select.mode
                if not action.auto_select.value_key:
                    key_names = {
                        AUTO_SELECT_CASE: _('Case property'),
                        AUTO_SELECT_FIXTURE: _('Lookup Table field'),
                        AUTO_SELECT_USER: _('custom user property'),
                        AUTO_SELECT_RAW: _('custom XPath expression'),
                    }
                    if mode in key_names:
                        errors.append({'type': 'auto select key', 'key_name': key_names[mode]})

                if not action.auto_select.value_source:
                    source_names = {
                        AUTO_SELECT_CASE: _('Case tag'),
                        AUTO_SELECT_FIXTURE: _('Lookup Table tag'),
                    }
                    if mode in source_names:
                        errors.append({'type': 'auto select source', 'source_name': source_names[mode]})
                elif mode == AUTO_SELECT_CASE:
                    case_tag = action.auto_select.value_source
                    if not self.form.actions.get_action_from_tag(case_tag):
                        errors.append({'type': 'auto select case ref', 'case_tag': action.case_tag})

            errors.extend(self.check_case_properties(
                all_names=action.get_property_names(),
                case_tag=action.case_tag
            ))

        if self.form.form_filter:
            # Replace any dots with #case, which doesn't make for valid xpath
            # but will trigger any appropriate validation errors
            interpolated_form_filter = interpolate_xpath(self.form.form_filter, case_xpath="#case",
                    module=self.form.get_module(), form=self.form)

            form_filter_references_case = (
                xpath_references_case(interpolated_form_filter) or
                xpath_references_user_case(interpolated_form_filter)
            )

            if form_filter_references_case:
                if not any(action for action in self.form.actions.load_update_cases if not action.auto_select):
                    errors.append({'type': "filtering without case"})

        def generate_paths():
            for action in self.form.actions.get_all_actions():
                for path in action.get_paths():
                    yield path

            if self.form.schedule:
                if self.form.schedule.transition_condition.type == 'if':
                    yield self.form.schedule.transition_condition.question
                if self.form.schedule.termination_condition.type == 'if':
                    yield self.form.schedule.termination_condition.question

        errors.extend(self.check_paths(generate_paths()))

        return errors
示例#17
0
    def check_actions(self):
        errors = []

        from corehq.apps.app_manager.models import AdvancedOpenCaseAction, LoadUpdateAction

        for action in self.form.actions.get_subcase_actions():
            case_tags = self.form.actions.get_case_tags()
            for case_index in action.case_indices:
                if case_index.tag not in case_tags:
                    errors.append({'type': 'missing parent tag', 'case_tag': case_index.tag})
                if case_index.relationship == 'question' and not case_index.relationship_question:
                    errors.append({'type': 'missing relationship question', 'case_tag': case_index.tag})

            if isinstance(action, AdvancedOpenCaseAction):
                if not action.name_path:
                    errors.append({'type': 'case_name required', 'case_tag': action.case_tag})

                for case_index in action.case_indices:
                    meta = self.form.actions.actions_meta_by_tag.get(case_index.tag)
                    if meta and meta['type'] == 'open' and meta['action'].repeat_context:
                        if (
                            not action.repeat_context or
                            not action.repeat_context.startswith(meta['action'].repeat_context)
                        ):
                            errors.append({'type': 'subcase repeat context',
                                           'case_tag': action.case_tag,
                                           'parent_tag': case_index.tag})

            errors.extend(self.check_case_properties(
                subcase_names=action.get_property_names(),
                case_tag=action.case_tag
            ))

        for action in self.form.actions.get_all_actions():
            if not action.case_type and (not isinstance(action, LoadUpdateAction) or not action.auto_select):
                errors.append({'type': "no case type in action", 'case_tag': action.case_tag})

            if isinstance(action, LoadUpdateAction) and action.auto_select:
                mode = action.auto_select.mode
                if not action.auto_select.value_key:
                    key_names = {
                        AUTO_SELECT_CASE: _('Case property'),
                        AUTO_SELECT_FIXTURE: _('Lookup Table field'),
                        AUTO_SELECT_USER: _('custom user property'),
                        AUTO_SELECT_RAW: _('custom XPath expression'),
                    }
                    if mode in key_names:
                        errors.append({'type': 'auto select key', 'key_name': key_names[mode]})

                if not action.auto_select.value_source:
                    source_names = {
                        AUTO_SELECT_CASE: _('Case tag'),
                        AUTO_SELECT_FIXTURE: _('Lookup Table tag'),
                    }
                    if mode in source_names:
                        errors.append({'type': 'auto select source', 'source_name': source_names[mode]})
                elif mode == AUTO_SELECT_CASE:
                    case_tag = action.auto_select.value_source
                    if not self.form.actions.get_action_from_tag(case_tag):
                        errors.append({'type': 'auto select case ref', 'case_tag': action.case_tag})

            errors.extend(self.check_case_properties(
                all_names=action.get_property_names(),
                case_tag=action.case_tag
            ))

        if self.form.form_filter:
            # Replace any dots with #case, which doesn't make for valid xpath
            # but will trigger any appropriate validation errors
            interpolated_form_filter = interpolate_xpath(self.form.form_filter, case_xpath="#case",
                    module=self.form.get_module(), form=self.form)

            form_filter_references_case = (
                xpath_references_case(interpolated_form_filter) or
                xpath_references_user_case(interpolated_form_filter)
            )

            if form_filter_references_case:
                if not any(action for action in self.form.actions.load_update_cases if not action.auto_select):
                    errors.append({'type': "filtering without case"})

        def generate_paths():
            for action in self.form.actions.get_all_actions():
                for path in action.get_paths():
                    yield path

            if self.form.schedule:
                if self.form.schedule.transition_condition.type == 'if':
                    yield self.form.schedule.transition_condition.question
                if self.form.schedule.termination_condition.type == 'if':
                    yield self.form.schedule.termination_condition.question

        errors.extend(self.check_paths(generate_paths()))

        return errors