Example #1
0
def get_apps_modules(domain, current_app_id=None, current_module_id=None, app_doc_types=('Application',)):
    """
    Returns a domain's Applications and their modules.

    If current_app_id and current_module_id are given, "is_current" is
    set to True for them. The interface uses this to select the current
    app and module by default.

    Linked and remote apps are omitted. Use the app_doc_types parameter
    to change this behaviour. (Deleted apps are not returned because the
    underlying Couch view doesn't include them.)
    """
    return [
        {
            'app_id': app.id,
            'name': app.name,
            'is_current': app.id == current_app_id,
            'modules': [{
                'module_id': module.id,
                'name': clean_trans(module.name, app.langs),
                'is_current': module.unique_id == current_module_id,
            } for module in app.modules]
        }
        for app in get_apps_in_domain(domain)
        # No linked, deleted or remote apps. (Use app.doc_type not
        # app.get_doc_type() so that the suffix isn't dropped.)
        if app.doc_type in app_doc_types
    ]
Example #2
0
def get_apps_modules(domain, current_app_id=None, current_module_id=None, app_doc_types=('Application',)):
    """
    Returns a domain's Applications and their modules.

    If current_app_id and current_module_id are given, "is_current" is
    set to True for them. The interface uses this to select the current
    app and module by default.

    Linked and remote apps are omitted. Use the app_doc_types parameter
    to change this behaviour. (Deleted apps are not returned because the
    underlying Couch view doesn't include them.)
    """
    return [
        {
            'app_id': app.id,
            'name': app.name,
            'is_current': app.id == current_app_id,
            'modules': [{
                'module_id': module.id,
                'name': clean_trans(module.name, app.langs),
                'is_current': module.unique_id == current_module_id,
            } for module in app.get_modules()]
        }
        for app in get_apps_in_domain(domain)
        # No linked, deleted or remote apps. (Use app.doc_type not
        # app.get_doc_type() so that the suffix isn't dropped.)
        if app.doc_type in app_doc_types
    ]
Example #3
0
    def all_media(self, lang=None):
        kwargs = self.get_media_ref_kwargs()
        media = []

        media.extend(self.menu_media(self, lang=lang))

        # Registration from case list
        if self.case_list_form.form_id:
            media.extend(self.menu_media(self.case_list_form, lang=lang))

        # Case list menu item
        if hasattr(self, 'case_list') and self.case_list.show:
            media.extend(self.menu_media(self.case_list, lang=lang))

        for name, details, display in self.get_details():
            # Case list lookup - not language-specific
            if display and details.display == 'short' and details.lookup_enabled and details.lookup_image:
                media.append(
                    ApplicationMediaReference(details.lookup_image,
                                              media_class=CommCareImage,
                                              is_menu_media=True,
                                              **kwargs))

            # Print template - not language-specific
            if display and details.display == 'long' and details.print_template:
                media.append(
                    ApplicationMediaReference(details.print_template['path'],
                                              media_class=CommCareMultimedia,
                                              **kwargs))

            # Icon-formatted columns
            for column in details.get_columns():
                if column.format == 'enum-image':
                    for map_item in column.enum:
                        icon = clean_trans(map_item.value,
                                           [lang] + self.get_app().langs)
                        if icon:
                            media.append(
                                ApplicationMediaReference(
                                    icon,
                                    media_class=CommCareImage,
                                    is_menu_media=True,
                                    **kwargs))

        return media
Example #4
0
def get_casedb_schema(form):
    """Get case database schema definition for vellum to display as an external data source.

    This lists all case types and their properties for the given app.
    """
    app = form.get_app()

    subsets = []
    if form.requires_case() and not form.get_module().search_config.data_registry:
        subsets.extend(_get_case_schema_subsets(app, form.get_module().case_type))

    parent_select = getattr(form.get_module(), 'parent_select', None)
    if parent_select and parent_select.active and parent_select.relationship is None:
        # for child modules that use parent select where the parent is not a 'related' case
        # See toggles.NON_PARENT_MENU_SELECTION
        parent_module = app.get_module_by_unique_id(parent_select.module_id)
        source = clean_trans(parent_module.name, app.langs)
        subsets.extend(_get_case_schema_subsets(app, parent_module.case_type, source=source))


    if is_usercase_in_use(app.domain):
        subsets.append({
            "id": USERCASE_TYPE,
            "name": "user",
            "key": "@case_type",
            "structure": {p: {} for p in get_usercase_properties(app)[USERCASE_TYPE]},
        })

    return {
        "id": "casedb",
        "uri": "jr://instance/casedb",
        "name": "case",
        "path": "/casedb/case",
        "structure": {},
        "subsets": subsets,
    }
Example #5
0
 def trans(d):
     return clean_trans(d, langs)
Example #6
0
def _edit_form_attr(request, domain, app_id, form_unique_id, attr):
    """
    Called to edit any (supported) form attribute, given by attr

    """

    ajax = json.loads(request.POST.get('ajax', 'true'))
    resp = {}

    app = get_app(domain, app_id)
    try:
        form = app.get_form(form_unique_id)
    except FormNotFoundException as e:
        if ajax:
            return HttpResponseBadRequest(str(e))
        else:
            messages.error(request, _("There was an error saving, please try again!"))
            return back_to_main(request, domain, app_id=app_id)
    lang = request.COOKIES.get('lang', app.langs[0])

    def should_edit(attribute):
        return attribute in request.POST

    if 'sha1' in request.POST and (should_edit("xform") or "xform" in request.FILES):
        conflict = _get_xform_conflict_response(form, request.POST['sha1'])
        if conflict is not None:
            return conflict

    if should_edit("name"):
        name = request.POST['name']
        form.name[lang] = name
        if not form.form_type == "shadow_form":
            xform = form.wrapped_xform()
            if xform.exists():
                xform.set_name(name)
                save_xform(app, form, xform.render())
        resp['update'] = {'.variable-form_name': clean_trans(form.name, [lang])}

    if should_edit('comment'):
        form.comment = request.POST['comment']

    if should_edit("xform") or "xform" in request.FILES:
        try:
            # support FILES for upload and POST for ajax post from Vellum
            try:
                xform = request.FILES.get('xform').read()
            except Exception:
                xform = request.POST.get('xform')
            else:
                try:
                    xform = str(xform, encoding="utf-8")
                except Exception:
                    raise Exception("Error uploading form: Please make sure your form is encoded in UTF-8")

            if request.POST.get('cleanup', False):
                try:
                    # First, we strip all newlines and reformat the DOM.
                    px = parseString(xform.replace('\r\n', '')).toprettyxml()
                    # Then we remove excess newlines from the DOM output.
                    text_re = re.compile(r'>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
                    prettyXml = text_re.sub(r'>\g<1></', px)
                    xform = prettyXml
                except Exception:
                    pass
            if xform:
                if isinstance(xform, str):
                    xform = xform.encode('utf-8')
                save_xform(app, form, xform)
            else:
                raise Exception("You didn't select a form to upload")
        except Exception as e:
            notify_exception(request, str(e))
            if ajax:
                return HttpResponseBadRequest(str(e))
            else:
                messages.error(request, str(e))
    if should_edit("references") or should_edit("case_references"):
        form.case_references = _get_case_references(request.POST)
    if should_edit("show_count"):
        show_count = request.POST['show_count']
        form.show_count = True if show_count == "True" else False
    if should_edit("put_in_root"):
        put_in_root = request.POST['put_in_root']
        form.put_in_root = True if put_in_root == "True" else False
    if should_edit('form_filter'):
        form.form_filter = request.POST['form_filter']
    if should_edit('post_form_workflow'):
        form.post_form_workflow = request.POST['post_form_workflow']
    if should_edit('auto_gps_capture'):
        form.auto_gps_capture = request.POST['auto_gps_capture'] == 'true'
    if should_edit('is_release_notes_form'):
        form.is_release_notes_form = request.POST['is_release_notes_form'] == 'true'
    if should_edit('enable_release_notes'):
        form.enable_release_notes = request.POST['enable_release_notes'] == 'true'
        if not form.is_release_notes_form and form.enable_release_notes:
            return json_response(
                {'message': _("You can't enable a form as release notes without allowing it as "
                    "a release notes form <TODO messaging>")},
                status_code=400
            )
    if (should_edit("form_links_xpath_expressions")
            and should_edit("form_links_form_ids")
            and toggles.FORM_LINK_WORKFLOW.enabled(domain)):
        form_links = zip(
            request.POST.getlist('form_links_xpath_expressions'),
            request.POST.getlist('form_links_form_ids'),
            [
                json.loads(datum_json) if datum_json else []
                for datum_json in request.POST.getlist('datums_json')
            ],
        )
        module_unique_ids = [m.unique_id for m in app.get_modules()]
        form.form_links = [FormLink(
            xpath=link[0],
            form_id=link[1] if link[1] not in module_unique_ids else None,
            module_unique_id=link[1] if link[1] in module_unique_ids else None,
            datums=[
                FormDatum(name=datum['name'], xpath=datum['xpath'])
                for datum in link[2]
            ]
        ) for link in form_links]

    if should_edit('post_form_workflow_fallback'):
        form.post_form_workflow_fallback = request.POST.get('post_form_workflow_fallback')

    if should_edit('custom_instances'):
        instances = json.loads(request.POST.get('custom_instances'))
        try:  # validate that custom instances can be added into the XML
            for instance in instances:
                etree.fromstring(
                    "<instance id='{}' src='{}' />".format(
                        instance.get('instanceId'),
                        instance.get('instancePath')
                    )
                )
        except etree.XMLSyntaxError as error:
            return json_response(
                {'message': _("There was an issue with your custom instances: {}").format(error)},
                status_code=400
            )

        form.custom_instances = [
            CustomInstance(
                instance_id=instance.get("instanceId"),
                instance_path=instance.get("instancePath"),
            ) for instance in instances
        ]

    if should_edit('custom_assertions'):
        assertions = json.loads(request.POST.get('custom_assertions'))
        try:  # validate that custom assertions can be added into the XML
            for assertion in assertions:
                etree.fromstring(
                    '<assertion test="{test}"><text><locale id="abc.def"/>{text}</text></assertion>'.format(
                        **assertion
                    )
                )
        except etree.XMLSyntaxError as error:
            return json_response(
                {'message': _("There was an issue with your custom assertions: {}").format(error)},
                status_code=400
            )

        existing_assertions = {assertion.test: assertion for assertion in form.custom_assertions}
        new_assertions = []
        for assertion in assertions:
            try:
                new_assertion = existing_assertions[assertion.get('test')]
                new_assertion.text[lang] = assertion.get('text')
            except KeyError:
                new_assertion = CustomAssertion(
                    test=assertion.get('test'),
                    text={lang: assertion.get('text')}
                )
            new_assertions.append(new_assertion)

        form.custom_assertions = new_assertions

    if should_edit("shadow_parent"):
        form.shadow_parent_form_id = request.POST['shadow_parent']

    if should_edit("custom_icon_form"):
        error_message = handle_custom_icon_edits(request, form, lang)
        if error_message:
            return json_response(
                {'message': error_message},
                status_code=400
            )

    if should_edit('session_endpoint_id'):
        raw_endpoint_id = request.POST['session_endpoint_id']
        try:
            set_session_endpoint(form, raw_endpoint_id, app)
        except InvalidSessionEndpoint as e:
            return json_response({'message': str(e)}, status_code=400)

    if should_edit('function_datum_endpoints'):
        if request.POST['function_datum_endpoints']:
            form.function_datum_endpoints = request.POST['function_datum_endpoints'].replace(" ", "").split(",")
        else:
            form.function_datum_endpoints = []

    handle_media_edits(request, form, should_edit, resp, lang)

    app.save(resp)
    notify_form_changed(domain, request.couch_user, app_id, form_unique_id)
    if ajax:
        return HttpResponse(json.dumps(resp))
    else:
        return back_to_main(request, domain, app_id=app_id, form_unique_id=form_unique_id)
Example #7
0
 def trans(d):
     return clean_trans(d, langs)
Example #8
0
def get_session_schema(form):
    """Get form session schema definition
    """
    from corehq.apps.app_manager.suite_xml.sections.entries import EntriesHelper
    app = form.get_app()
    structure = {}
    datums = EntriesHelper(app).get_datums_meta_for_form_generic(form)
    datums = [
        d for d in datums
        if d.requires_selection and d.case_type and not d.is_new_case_id
    ]

    def _get_structure(datum, data_registry, source=None):
        id_source = f":{slugify(source)}" if source else ""
        return {
            "reference": {
                "hashtag": f'#registry_case{id_source}'
                if data_registry else f"#case{id_source}",
                "source": "registry" if data_registry else "casedb",
                "subset": f"case{id_source}",
                "key": "@case_id",
            },
        }

    unrelated_parents = set()
    for datum in datums:
        if not datum.module_id:
            continue
        module = app.get_module_by_unique_id(datum.module_id)
        parent_select_active = hasattr(
            module, 'parent_select') and module.parent_select.active
        if parent_select_active and module.parent_select.relationship is None:
            # for child modules that use parent select where the parent is not a 'related' case
            # See toggles.NON_PARENT_MENU_SELECTION
            unrelated_parents.add(module.parent_select.module_id)

    data_structure = {}
    for i, datum in enumerate(reversed(datums)):
        if isinstance(datum.datum, InstanceDatum):
            continue
        module_id = datum.module_id
        module = app.get_module_by_unique_id(module_id) if module_id else None
        data_registry = module.search_config.data_registry if module else None
        if i == 0:
            # always add the datum for this module
            data_structure[datum.datum.id] = _get_structure(
                datum, data_registry)
        else:
            if module and module_id in unrelated_parents:
                source = clean_trans(
                    module.name, app.langs
                )  # ensure that this structure reference is unique
                data_structure[datum.datum.id] = _get_structure(
                    datum, data_registry, source)

    if data_structure:
        structure["data"] = {
            "merge": True,
            "structure": data_structure,
        }

    if is_usercase_in_use(app.domain):
        structure["context"] = {
            "merge": True,
            "structure": {
                "userid": {
                    "reference": {
                        "hashtag": "#user",
                        "source": "casedb",
                        "subset": USERCASE_TYPE,
                        "subset_key": "@case_type",
                        "subset_filter": True,
                        "key": "hq_user_id",
                    },
                },
            },
        }
    return {
        "id": "commcaresession",
        "uri": "jr://instance/session",
        "name": "Session",
        "path": "/session",
        "structure": structure,
    }