<commit_before>from collections import namedtuple
from django_prbac.utils import has_privilege as prbac_has_privilege
from django.utils.translation import ugettext_lazy as _

from dimagi.utils.decorators.memoized import memoized

from corehq import feature_previews
from corehq.apps.app_manager.exceptions import AddOnNotFoundException
from corehq.apps.app_manager.models import Module, AdvancedModule, CareplanModule, ShadowModule
from corehq.privileges import LOOKUP_TABLES

class AddOn(object):
    def __init__(self, name, description, help_link=None, privilege=None, used_in_module=None, used_in_form=None):
        self.name = name
        self.description = description
        self.help_link = help_link
        self.privilege = privilege

        self.used_in_module = used_in_module if used_in_module else lambda m: False
        self.used_in_form = used_in_form if used_in_form else lambda f: False

def _uses_detail_format(module, column_format):
    details = []
    if isinstance(module, Module) or isinstance(module, ShadowModule):
        details = [module.case_details, module.ref_details]
    elif isinstance(module, AdvancedModule):
        details = [module.case_details, module.product_details]
    elif isinstance(module, CareplanModule):
        details = [module.goal_details, module.task_details]
    return any([c.format for d in details for c in d.short.columns + d.long.columns if c.format == column_format])

_ADD_ONS = {
    "advanced_itemsets": AddOn(
        name=feature_previews.VELLUM_ADVANCED_ITEMSETS.label,
        description=feature_previews.VELLUM_ADVANCED_ITEMSETS.description,
        privilege=LOOKUP_TABLES,
    ),
    "calc_xpaths": AddOn(
        name=feature_previews.CALC_XPATHS.label,
        description=feature_previews.CALC_XPATHS.description,
        used_in_module=lambda m: _uses_detail_format(m, 'calculate'),
    ),
    "case_detail_overwrite": AddOn(
        name=_("Case Detail Overwrite"),
        description=_("Ability to overwrite one case list or detail's settings with another's. Available in case menu's settings."),
    ),
    "case_list_menu_item": AddOn(
        name=_("Case List Menu Item"),
        description=_("Allows the mobile user to view the case list and case details without actually opening a form. Available in the case menu's settings."),
        used_in_module=lambda m: isinstance(m, Module) and (m.case_list.show or m.task_list.show),  # TODO: will this break anything?
    ),
    "conditional_enum": AddOn(
        name=feature_previews.CONDITIONAL_ENUM.label,
        description=feature_previews.CONDITIONAL_ENUM.description,
        used_in_module=lambda m: _uses_detail_format(m, 'conditional-enum'),
    ),
    "conditional_form_actions": AddOn(
        name=_('Case Conditions'),
        description=_("Open or close a case only if a specific question has a particular answer. Available in form settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Case+Configuration",
        used_in_form=lambda f: f.actions.open_case.condition.type == 'if' or f.actions.close_case.condition.type, # TODO: will this break advanced forms?
    ),
    "form_display_conditions": AddOn(
        name=_("Form Display Conditions"),
        description=_("Write logic to show or hide forms on the mobile device. Available in form settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Form+Display+Conditions",
        used_in_form=lambda f: bool(f.form_filter),
    ),
    "edit_form_actions": AddOn(
        name=_("Edit Form Actions"),
        description=_("Allow changing form actions. Available in form settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Case+Configuration",
    ),
    "enum_image": AddOn(
        name=feature_previews.ENUM_IMAGE.label,
        description=feature_previews.ENUM_IMAGE.description,
        help_link=feature_previews.ENUM_IMAGE.help_link,
        used_in_module=lambda m: _uses_detail_format(m, 'enum-image'),
    ),
    "menu_mode": AddOn(
        name=_("Menu Mode"),
        description=_("Control whether a form's enclosing menu is displayed on the mobile device or not. Available in menu settings."),
        used_in_module=lambda m: m.put_in_root,
    ),
    "module_display_conditions": AddOn(
        name=_("Menu Display Conditions"),
        description=_("Write logic to show or hide menus on the mobile device. Available in menu settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Module+Filtering",
        used_in_module=lambda m: bool(m.module_filter),
    ),
    "register_from_case_list": AddOn(
        name=_("Register from case list"),
        description=_("Minimize duplicates by making registration forms available directly from the case list on the mobile device. Availabe in menu settings."),
        help_link="https://confluence.dimagi.com/pages/viewpage.action?pageId=30605985",
        used_in_module=lambda m: m.case_list_form.form_id, # TODO: break anything?
    ),
    "subcases": AddOn(
        name=_("Child Cases"),
        description=_("Open other types of cases for use in other modules, linking them to the case that created them. Available in form settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Child+Cases",
        used_in_form=lambda f: bool(f.actions.subcases),    # TODO: will this break anything?
    ),
    "unstructured_case_lists": AddOn(
        name=_("Customize Case List Registration"),
        description=_("Create new case lists without a registration form, and allow deletion of registration forms."),
    ),
}<commit_msg>Make some used_in_foo subs handle different types of modules/forms<commit_after>from collections import namedtuple
from django_prbac.utils import has_privilege as prbac_has_privilege
from django.utils.translation import ugettext_lazy as _

from dimagi.utils.decorators.memoized import memoized

from corehq import feature_previews
from corehq.apps.app_manager.exceptions import AddOnNotFoundException
from corehq.apps.app_manager.models import Module, AdvancedModule, CareplanModule, ShadowModule
from corehq.privileges import LOOKUP_TABLES

class AddOn(object):
    def __init__(self, name, description, help_link=None, privilege=None, used_in_module=None, used_in_form=None):
        self.name = name
        self.description = description
        self.help_link = help_link
        self.privilege = privilege

        self.used_in_module = used_in_module if used_in_module else lambda m: False
        self.used_in_form = used_in_form if used_in_form else lambda f: False

def _uses_case_list_menu_item(module):
    if getattr(module, 'case_list', False) and module.case_list.show:
        return True
    if getattr(module, 'task_list', False) and module.task_list.show:
        return True
    if getattr(module, 'referral_list', False) and module.referral_list.show:
        return True
    return False

def _uses_conditional_form_actions(form):
    if form.form_type != 'module_form':
        # Don't bother restricting non-basic forms
        return True
    return form.actions.open_case.condition.type == 'if' or form.actions.close_case.condition.type == 'if',

def _uses_detail_format(module, column_format):
    details = []
    if isinstance(module, Module) or isinstance(module, ShadowModule):
        details = [module.case_details, module.ref_details]
    elif isinstance(module, AdvancedModule):
        details = [module.case_details, module.product_details]
    elif isinstance(module, CareplanModule):
        details = [module.goal_details, module.task_details]
    return any([c.format for d in details for c in d.short.columns + d.long.columns if c.format == column_format])

_ADD_ONS = {
    "advanced_itemsets": AddOn(
        name=feature_previews.VELLUM_ADVANCED_ITEMSETS.label,
        description=feature_previews.VELLUM_ADVANCED_ITEMSETS.description,
        privilege=LOOKUP_TABLES,
    ),
    "calc_xpaths": AddOn(
        name=feature_previews.CALC_XPATHS.label,
        description=feature_previews.CALC_XPATHS.description,
        used_in_module=lambda m: _uses_detail_format(m, 'calculate'),
    ),
    "case_detail_overwrite": AddOn(
        name=_("Case Detail Overwrite"),
        description=_("Ability to overwrite one case list or detail's settings with another's. Available in case menu's settings."),
    ),
    "case_list_menu_item": AddOn(
        name=_("Case List Menu Item"),
        description=_("Allows the mobile user to view the case list and case details without actually opening a form. Available in the case menu's settings."),
        used_in_module=lambda m: _uses_case_list_menu_item(m),
    ),
    "conditional_enum": AddOn(
        name=feature_previews.CONDITIONAL_ENUM.label,
        description=feature_previews.CONDITIONAL_ENUM.description,
        used_in_module=lambda m: _uses_detail_format(m, 'conditional-enum'),
    ),
    "conditional_form_actions": AddOn(
        name=_('Case Conditions'),
        description=_("Open or close a case only if a specific question has a particular answer. Available in form settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Case+Configuration",
        used_in_form=lambda f: _uses_conditional_form_actions(f)
    ),
    "form_display_conditions": AddOn(
        name=_("Form Display Conditions"),
        description=_("Write logic to show or hide forms on the mobile device. Available in form settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Form+Display+Conditions",
        used_in_form=lambda f: bool(f.form_filter),
    ),
    "edit_form_actions": AddOn(
        name=_("Edit Form Actions"),
        description=_("Allow changing form actions. Available in form settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Case+Configuration",
    ),
    "enum_image": AddOn(
        name=feature_previews.ENUM_IMAGE.label,
        description=feature_previews.ENUM_IMAGE.description,
        help_link=feature_previews.ENUM_IMAGE.help_link,
        used_in_module=lambda m: _uses_detail_format(m, 'enum-image'),
    ),
    "menu_mode": AddOn(
        name=_("Menu Mode"),
        description=_("Control whether a form's enclosing menu is displayed on the mobile device or not. Available in menu settings."),
        used_in_module=lambda m: getattr(m, 'put_in_root', False),
    ),
    "module_display_conditions": AddOn(
        name=_("Menu Display Conditions"),
        description=_("Write logic to show or hide menus on the mobile device. Available in menu settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Module+Filtering",
        used_in_module=lambda m: bool(m.module_filter),
    ),
    "register_from_case_list": AddOn(
        name=_("Register from case list"),
        description=_("Minimize duplicates by making registration forms available directly from the case list on the mobile device. Availabe in menu settings."),
        help_link="https://confluence.dimagi.com/pages/viewpage.action?pageId=30605985",
        used_in_module=lambda m: m.case_list_form.form_id,
    ),
    "subcases": AddOn(
        name=_("Child Cases"),
        description=_("Open other types of cases for use in other modules, linking them to the case that created them. Available in form settings."),
        help_link="https://confluence.dimagi.com/display/commcarepublic/Child+Cases",
        used_in_form=lambda f: bool(f.actions.subcases),
    ),
    "unstructured_case_lists": AddOn(
        name=_("Customize Case List Registration"),
        description=_("Create new case lists without a registration form, and allow deletion of registration forms."),
    ),
}
{'fraction_non_alphanumeric': 0.095784463708992, 'fraction_numerical': 0.00135985041645419, 'mean_word_length': 3.844380403458213, 'pattern_counts': {'":': 28, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 12, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '909461', 'n_tokens_mistral': 3451, 'n_tokens_neox': 3421, 'n_words': 859}