def get_module_template(domain, module): if isinstance(module, CareplanModule): return get_app_manager_template( domain, "app_manager/v1/module_view_careplan.html", "app_manager/v2/module_view_careplan.html", ) elif isinstance(module, AdvancedModule): return get_app_manager_template( domain, "app_manager/v1/module_view_advanced.html", "app_manager/v2/module_view_advanced.html", ) elif isinstance(module, ReportModule): return get_app_manager_template( domain, 'app_manager/v1/module_view_report.html', 'app_manager/v2/module_view_report.html', ) else: return get_app_manager_template( domain, "app_manager/v1/module_view.html", "app_manager/v2/module_view.html", )
def _load_custom_commcare_settings(user=None): path = os.path.join(os.path.dirname(__file__), 'static', 'app_manager', 'json') settings = [] with open( os.path.join( path, get_app_manager_template( user, 'v1/commcare-profile-settings.yaml', 'v2/commcare-profile-settings.yaml'))) as f: for setting in yaml.load(f): if not setting.get('type'): setting['type'] = 'properties' settings.append(setting) with open( os.path.join( path, get_app_manager_template( user, 'v1/commcare-app-settings.yaml', 'v2/commcare-app-settings.yaml'))) as f: for setting in yaml.load(f): if not setting.get('type'): setting['type'] = 'hq' settings.append(setting) for setting in settings: if not setting.get('widget'): setting['widget'] = 'select' for prop in PROFILE_SETTINGS_TO_TRANSLATE: if prop in setting: setting[prop] = _translate_setting(setting, prop) return settings
def _load_custom_commcare_settings(domain=None): path = os.path.join(os.path.dirname(__file__), 'static', 'app_manager', 'json') settings = [] with open(os.path.join( path, get_app_manager_template( domain, 'v1/commcare-profile-settings.yaml', 'v2/commcare-profile-settings.yaml' ) )) as f: for setting in yaml.load(f): if not setting.get('type'): setting['type'] = 'properties' settings.append(setting) with open(os.path.join(path, get_app_manager_template( domain, 'v1/commcare-app-settings.yaml', 'v2/commcare-app-settings.yaml' ))) as f: for setting in yaml.load(f): if not setting.get('type'): setting['type'] = 'hq' settings.append(setting) for setting in settings: if not setting.get('widget'): setting['widget'] = 'select' # i18n; not statically analyzable setting['name'] = ugettext_noop(setting['name']) return settings
def _load_custom_commcare_settings(user=None): path = os.path.join(os.path.dirname(__file__), 'static', 'app_manager', 'json') settings = [] with open( os.path.join( path, get_app_manager_template( user, 'v1/commcare-profile-settings.yaml', 'v2/commcare-profile-settings.yaml'))) as f: for setting in yaml.load(f): if not setting.get('type'): setting['type'] = 'properties' settings.append(setting) with open( os.path.join( path, get_app_manager_template( user, 'v1/commcare-app-settings.yaml', 'v2/commcare-app-settings.yaml'))) as f: for setting in yaml.load(f): if not setting.get('type'): setting['type'] = 'hq' settings.append(setting) for setting in settings: if not setting.get('widget'): setting['widget'] = 'select' # i18n; not statically analyzable setting['name'] = ugettext_noop(setting['name']) return settings
def download_index(request, domain, app_id): """ A landing page, mostly for debugging, that has links the jad and jar as well as all the resource files that will end up zipped into the jar. """ template = get_app_manager_template( domain, "app_manager/v1/download_index.html", "app_manager/v2/download_index.html", ) files = [] try: files = source_files(request.app) except Exception: messages.error(request, _("We were unable to get your files " "because your Application has errors. " "Please click <strong>Make New Version</strong> " "under <strong>Deploy</strong> " "for feedback on how to fix these errors."), extra_tags='html') return render( request, template, { 'app': request.app, 'files': [{ 'name': f[0], 'source': f[1] } for f in files], 'supports_j2me': request.app.build_spec.supports_j2me(), })
def dispatch(self, request, *args, **kwargs): self.template_name = get_app_manager_template( request.user, self.template_name, 'app_manager/v2/app_diff.html', ) return super(AppDiffView, self).dispatch(request, *args, **kwargs)
def odk_install(request, domain, app_id, with_media=False): app = get_app(domain, app_id) qr_code_view = "odk_qr_code" if not with_media else "odk_media_qr_code" build_profile_id = request.GET.get('profile') profile_url = app.odk_profile_display_url if not with_media else app.odk_media_profile_display_url if build_profile_id is not None: profile_url += '?profile={profile}'.format(profile=build_profile_id) context = { "domain": domain, "app": app, "qr_code": reverse(qr_code_view, args=[domain, app_id], params={'profile': build_profile_id}), "profile_url": profile_url, } template = get_app_manager_template( request.user, "app_manager/v1/odk_install.html", "app_manager/v2/odk_install.html", ) return render(request, template, context)
def save_copy(request, domain, app_id): """ Saves a copy of the app to a new doc. See VersionedDoc.save_copy """ track_built_app_on_hubspot.delay(request.couch_user) comment = request.POST.get('comment') app = get_app(domain, app_id) try: errors = app.validate_app() except ModuleIdMissingException: # For apps (mainly Exchange apps) that lost unique_id attributes on Module app.ensure_module_unique_ids(should_save=True) errors = app.validate_app() if not errors: try: copy = app.make_build( comment=comment, user_id=request.couch_user.get_id, previous_version=app.get_latest_app(released_only=False)) copy.save(increment_version=False) finally: # To make a RemoteApp always available for building if app.is_remote_app(): app.save(increment_version=True) _track_build_for_app_preview(domain, request.couch_user, app_id, 'User created a build') else: copy = None copy = copy and SavedAppBuild.wrap(copy.to_json()).to_saved_build_json( get_timezone_for_user(request.couch_user, domain)) lang, langs = get_langs(request, app) if copy: # Set if build is supported for Java Phones j2me_enabled_configs = CommCareBuildConfig.j2me_enabled_config_labels() copy['j2me_enabled'] = copy['menu_item_label'] in j2me_enabled_configs template = get_app_manager_template( request.user, "app_manager/v1/partials/build_errors.html", "app_manager/v2/partials/build_errors.html", ) return json_response({ "saved_app": copy, "error_html": render_to_string( template, { 'request': request, 'app': get_app(domain, app_id), 'build_errors': errors, 'domain': domain, 'langs': langs, 'lang': lang }), })
def validate_module_for_build(request, domain, app_id, module_id, ajax=True): app = get_app(domain, app_id) try: module = app.get_module(module_id) except ModuleNotFoundException: raise Http404() errors = module.validate_for_build() lang, langs = get_langs(request, app) response_html = render_to_string( get_app_manager_template( domain, 'app_manager/v1/partials/build_errors.html', 'app_manager/v2/partials/build_errors.html', ), { 'request': request, 'app': app, 'build_errors': errors, 'not_actual_build': True, 'domain': domain, 'langs': langs, 'lang': lang }) if ajax: return json_response({'error_html': response_html}) return HttpResponse(response_html)
def multimedia_ajax(request, domain, app_id): template = get_app_manager_template( domain, 'app_manager/v1/partials/multimedia_ajax.html', 'app_manager/v2/partials/multimedia_ajax.html', ) app = get_app(domain, app_id) if app.get_doc_type() == 'Application': try: multimedia_state = app.check_media_state() except ProcessTimedOut: notify_exception(request) messages.warning( request, ("We were unable to check if your forms had errors. " "Refresh the page and we will try again.")) multimedia_state = { 'has_media': False, 'has_form_errors': True, 'has_missing_refs': False, } context = { 'multimedia_state': multimedia_state, 'domain': domain, 'app': app, } return render(request, template, context) else: raise Http404()
def dispatch(self, request, *args, **kwargs): self.template_name = get_app_manager_template( self.domain, self.template_name, 'app_manager/v2/summary.html', ) return super(AppSummaryView, self).dispatch(request, *args, **kwargs)
def _load_commcare_settings_layout(doc_type, user): settings = dict([('{0}.{1}'.format(setting.get('type'), setting.get('id')), setting) for setting in _load_custom_commcare_settings(user)]) path = os.path.join(os.path.dirname(__file__), 'static', 'app_manager', 'json') with open( os.path.join( path, get_app_manager_template( user, 'v1/commcare-settings-layout.yaml', 'v2/commcare-settings-layout.yaml'))) as f: layout = yaml.load(f) for section in layout: # i18n; not statically analyzable section['title'] = ugettext_noop(section['title']) for i, key in enumerate(section['settings']): setting = settings.pop(key) if doc_type == 'Application' or setting['type'] == 'hq': section['settings'][i] = setting else: section['settings'][i] = None section['settings'] = filter(None, section['settings']) for setting in section['settings']: setting['value'] = None if settings: raise Exception("CommCare settings layout should mention " "all the available settings. " "The following settings went unmentioned: %s" % (', '.join(settings.keys()))) return layout
def import_app(request, domain): template = get_app_manager_template( domain, "app_manager/v1/import_app.html", "app_manager/v2/import_app.html", ) if request.method == "POST": clear_app_cache(request, domain) name = request.POST.get('name') compressed = request.POST.get('compressed') valid_request = True if not name: messages.error(request, _("You must submit a name for the application you are importing.")) valid_request = False if not compressed: messages.error(request, _("You must submit the source data.")) valid_request = False if not valid_request: return render(request, template, {'domain': domain}) source = decompress([chr(int(x)) if int(x) < 256 else int(x) for x in compressed.split(',')]) source = json.loads(source) assert(source is not None) app = import_app_util(source, domain, {'name': name}) return back_to_main(request, domain, app_id=app._id) else: app_id = request.GET.get('app') redirect_domain = request.GET.get('domain') or None if redirect_domain is not None: redirect_domain = redirect_domain.lower() if Domain.get_by_name(redirect_domain): return HttpResponseRedirect( reverse('import_app', args=[redirect_domain]) + "?app={app_id}".format(app_id=app_id) ) else: if redirect_domain: messages.error(request, "We can't find a project called %s." % redirect_domain) else: messages.error(request, "You left the project name blank.") return HttpResponseRedirect(request.META.get('HTTP_REFERER', request.path)) if app_id: app = get_app(None, app_id) assert(app.get_doc_type() in ('Application', 'RemoteApp')) assert(request.couch_user.is_member_of(app.domain)) else: app = None return render(request, template, { 'domain': domain, 'app': app, })
def releases_ajax(request, domain, app_id): template = get_app_manager_template( request.user, "app_manager/v1/partials/releases.html", "app_manager/v2/partials/releases.html", ) context = get_releases_context(request, domain, app_id) response = render(request, template, context) response.set_cookie('lang', encode_if_unicode(context['lang'])) return response
def validate_form_for_build(request, domain, app_id, unique_form_id, ajax=True): app = get_app(domain, app_id) try: form = app.get_form(unique_form_id) except FormNotFoundException: # this can happen if you delete the form from another page raise Http404() errors = form.validate_for_build() lang, langs = get_langs(request, app) if ajax and "blank form" in [error.get('type') for error in errors ] and not form.form_type == "shadow_form": response_html = ("" if toggles.APP_MANAGER_V2.enabled( request.user.username) else render_to_string( 'app_manager/v1/partials/create_form_prompt.html')) else: if form.form_type == "shadow_form": # Don't display the blank form error if its a shadow form errors = [e for e in errors if e['type'] != "blank form"] response_html = render_to_string( get_app_manager_template( request.user, 'app_manager/v1/partials/build_errors.html', 'app_manager/v2/partials/build_errors.html', ), { 'request': request, 'app': app, 'form': form, 'build_errors': errors, 'not_actual_build': True, 'domain': domain, 'langs': langs, 'lang': lang }) if ajax: return json_response({ 'error_html': response_html, }) else: return HttpResponse(response_html)
def _load_commcare_settings_layout(doc_type, domain): settings = dict([ ('{0}.{1}'.format(setting.get('type'), setting.get('id')), setting) for setting in _load_custom_commcare_settings(domain) ]) path = os.path.join(os.path.dirname(__file__), 'static', 'app_manager', 'json') with open(os.path.join( path, get_app_manager_template( domain, 'v1/commcare-settings-layout.yaml', 'v2/commcare-settings-layout.yaml' ))) as f: layout = yaml.load(f) for section in layout: # i18n; not statically analyzable section['title'] = ugettext_noop(section['title']) for i, key in enumerate(section['settings']): setting = settings.pop(key) if doc_type == 'Application' or setting['type'] == 'hq': section['settings'][i] = setting else: section['settings'][i] = None section['settings'] = filter(None, section['settings']) for setting in section['settings']: setting['value'] = None if settings: raise Exception( "CommCare settings layout should mention " "all the available settings. " "The following settings went unmentioned: %s" % ( ', '.join(settings.keys()) ) ) return layout
def xform_display(request, domain, form_unique_id): try: form, app = Form.get_form(form_unique_id, and_app=True) except ResourceNotFound: raise Http404() if domain != app.domain: raise Http404() langs = [request.GET.get('lang')] + app.langs questions = form.get_questions(langs, include_triggers=True, include_groups=True) if request.GET.get('format') == 'html': questions = [FormQuestionResponse(q) for q in questions] template = get_app_manager_template( request.user, 'app_manager/v1/xform_display.html', 'app_manager/v2/xform_display.html', ) return render(request, template, {'questions': questions_in_hierarchy(questions)}) else: return json_response(questions)
def view_generic(request, domain, app_id=None, module_id=None, form_id=None, copy_app_form=None, release_manager=False): """ This is the main view for the app. All other views redirect to here. """ if form_id and not module_id: return bail(request, domain, app_id) app = module = form = None try: if app_id: app = get_app(domain, app_id) 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() if form_id: try: form = module.get_form(form_id) except IndexError: raise Http404() except ModuleNotFoundException: return bail(request, domain, app_id) # Application states that should no longer exist if app: if app.application_version == APP_V1: _assert = soft_assert() _assert(False, 'App version 1.0', { 'domain': domain, 'app_id': app_id }) template = get_app_manager_template( request.user, 'app_manager/v1/no_longer_supported.html', 'app_manager/v2/no_longer_supported.html', ) return render(request, template, { '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 toggles.USER_PROPERTY_EASY_REFS.enabled(domain) and "usercase_preload" in 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, 'form_id': form_id, }) context = get_apps_base_context(request, domain, app) if app and app.copy_of: # don't fail hard. return HttpResponseRedirect( reverse( "view_app", args=[domain, app.copy_of] # TODO - is this right? )) # grandfather in people who set commcare sense earlier if app and 'use_commcare_sense' in app: if app['use_commcare_sense']: if 'features' not in app.profile: app.profile['features'] = {} app.profile['features']['sense'] = 'true' del app['use_commcare_sense'] app.save() context.update({ 'module': module, 'form': form, }) lang = context['lang'] if app and not module and hasattr(app, 'translations'): context.update({"translations": app.translations.get(lang, {})}) if form: template, form_context = get_form_view_context_and_template( request, domain, form, context['langs']) 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(app, module, lang) context.update(module_context) elif app: context.update(get_app_view_context(request, app)) v2_template = ('app_manager/v2/app_view_release_manager.html' if release_manager else 'app_manager/v2/app_view_settings.html') template = get_app_manager_template(request.user, 'app_manager/v1/app_view.html', v2_template) if release_manager: context.update(get_releases_context(request, domain, app_id)) context.update({ 'is_app_settings_page': not release_manager, }) else: if toggles.APP_MANAGER_V2.enabled(request.user.username): from corehq.apps.dashboard.views import DomainDashboardView return HttpResponseRedirect( reverse(DomainDashboardView.urlname, args=[domain])) else: from corehq.apps.dashboard.views import NewUserDashboardView return HttpResponseRedirect( reverse(NewUserDashboardView.urlname, args=[domain])) # update multimedia context for forms and modules. menu_host = form or module if menu_host: default_file_name = 'module%s' % module_id if form_id: default_file_name = '%s_form%s' % (default_file_name, form_id) specific_media = { 'menu': { 'menu_refs': app.get_menu_media(module, module_id, form=form, form_index=form_id, to_language=lang), 'default_file_name': '{name}_{lang}'.format(name=default_file_name, lang=lang), } } if module 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['case_list_form'] = { 'menu_refs': app.get_case_list_form_media(module, module_id, to_language=lang), 'default_file_name': _make_name('case_list_form'), } specific_media['case_list_menu_item'] = { 'menu_refs': app.get_case_list_menu_item_media(module, module_id, to_language=lang), 'default_file_name': _make_name('case_list_menu_item'), } specific_media['case_list_lookup'] = { 'menu_refs': app.get_case_list_lookup_image(module, module_id), 'default_file_name': '{}_case_list_lookup'.format(default_file_name), } if hasattr(module, 'product_details'): specific_media['product_list_lookup'] = { 'menu_refs': app.get_case_list_lookup_image(module, module_id, type='product'), 'default_file_name': '{}_product_list_lookup'.format(default_file_name), } context.update({ 'multimedia': { "object_map": app.get_object_map(), 'upload_managers': { 'icon': MultimediaImageUploadController( "hqimage", reverse(ProcessImageFileUploadView.name, args=[app.domain, app.get_id])), 'audio': MultimediaAudioUploadController( "hqaudio", reverse(ProcessAudioFileUploadView.name, args=[app.domain, app.get_id])), }, } }) try: context['multimedia']['references'] = app.get_references() except ReportConfigurationNotFoundError: pass context['multimedia'].update(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)] domain_names.sort() if app and copy_app_form is None: toggle_enabled = toggles.EXPORT_ZIPPED_APPS.enabled( request.user.username) copy_app_form = CopyApplicationForm( domain, app, export_zipped_apps_enabled=toggle_enabled) context.update({ 'domain_names': domain_names, }) linked_apps_enabled = toggles.LINKED_APPS.enabled(domain) context.update({ 'copy_app_form': copy_app_form, 'linked_apps_enabled': linked_apps_enabled, }) context['latest_commcare_version'] = get_commcare_versions( request.user)[-1] if app and app.doc_type == 'Application' and has_privilege( request, privileges.COMMCARE_LOGO_UPLOADER): uploader_slugs = ANDROID_LOGO_PROPERTY_MAPPING.keys() from corehq.apps.hqmedia.controller import MultimediaLogoUploadController from corehq.apps.hqmedia.views import ProcessLogoFileUploadView uploaders = [ MultimediaLogoUploadController( slug, reverse( ProcessLogoFileUploadView.name, 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, module_id=app.logo_refs.get(slug, {}).get("m_id"), ).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) }, }) domain_obj = Domain.get_by_name(domain) context.update({ 'show_live_preview': app and should_show_preview_app(request, app, request.couch_user.username), 'can_preview_form': request.couch_user.has_permission(domain, 'edit_data') }) response = render(request, template, context) response.set_cookie('lang', encode_if_unicode(lang)) return response
def form_designer(request, domain, app_id, module_id=None, form_id=None): def _form_uses_case(module, form): return module and module.case_type and form.requires_case() def _form_is_basic(form): return form.doc_type == 'Form' def _form_too_large(app, form): # form less than 0.1MB, anything larger starts to have # performance issues with fullstory return app.blobs['{}.xml'.format( form.unique_id)]['content_length'] > 102400 meta = get_meta(request) track_entered_form_builder_on_hubspot.delay(request.couch_user, request.COOKIES, meta) app = get_app(domain, app_id) module = None try: module = app.get_module(module_id) except ModuleNotFoundException: return bail(request, domain, app_id, not_found="module") try: form = module.get_form(form_id) except IndexError: return bail(request, domain, app_id, not_found="form") if form.no_vellum: messages.warning( request, _("You tried to edit this form in the Form Builder. " "However, your administrator has locked this form against editing " "in the form builder, so we have redirected you to " "the form's front page instead.")) return back_to_main(request, domain, app_id=app_id, unique_form_id=form.unique_id) include_fullstory = False vellum_plugins = ["modeliteration", "itemset", "atwho"] if (toggles.COMMTRACK.enabled(domain)): vellum_plugins.append("commtrack") if toggles.VELLUM_SAVE_TO_CASE.enabled(domain): vellum_plugins.append("saveToCase") if (_form_uses_case(module, form) and _form_is_basic(form)): vellum_plugins.append("databrowser") vellum_features = toggles.toggles_dict(username=request.user.username, domain=domain) vellum_features.update(feature_previews.previews_dict(domain)) include_fullstory = not _form_too_large(app, form) vellum_features.update({ 'group_in_field_list': app.enable_group_in_field_list, 'image_resize': app.enable_image_resize, 'markdown_in_groups': app.enable_markdown_in_groups, 'lookup_tables': domain_has_privilege(domain, privileges.LOOKUP_TABLES), 'templated_intents': domain_has_privilege(domain, privileges.TEMPLATED_INTENTS), 'custom_intents': domain_has_privilege(domain, privileges.CUSTOM_INTENTS), 'rich_text': True, }) has_schedule = (getattr(module, 'has_schedule', False) and getattr(form, 'schedule', False) and form.schedule.enabled) scheduler_data_nodes = [] if has_schedule: scheduler_data_nodes = [ SCHEDULE_CURRENT_VISIT_NUMBER, SCHEDULE_NEXT_DUE, SCHEDULE_UNSCHEDULED_VISIT, SCHEDULE_GLOBAL_NEXT_VISIT_DATE, ] scheduler_data_nodes.extend([ u"next_{}".format(f.schedule_form_id) for f in form.get_phase().get_forms() if getattr(f, 'schedule', False) and f.schedule.enabled ]) if tours.VELLUM_CASE_MANAGEMENT.is_enabled( request.user) and form.requires_case(): request.guided_tour = tours.VELLUM_CASE_MANAGEMENT.get_tour_data() context = get_apps_base_context(request, domain, app) context.update(locals()) context.update({ 'vellum_debug': settings.VELLUM_DEBUG, 'nav_form': form, 'formdesigner': True, 'include_fullstory': include_fullstory, 'notifications_enabled': request.user.is_superuser, 'notify_facility': get_facility_for_form(domain, app_id, form.unique_id), }) notify_form_opened(domain, request.couch_user, app_id, form.unique_id) domain_obj = Domain.get_by_name(domain) 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'), }) core = { 'dataSourcesEndpoint': reverse('get_form_data_schema', kwargs={ 'domain': domain, 'form_unique_id': form.get_unique_id() }), 'dataSource': [ # DEPRECATED. Use dataSourcesEndpoint { 'key': 'fixture', 'name': 'Fixtures', 'endpoint': reverse('fixture_metadata', kwargs={'domain': domain}), }, ], 'form': form.source, 'formId': form.get_unique_id(), 'formName': trans(form.name, app.langs), 'saveType': 'patch', 'saveUrl': reverse('edit_form_attr', args=[domain, app.id, form.get_unique_id(), 'xform']), 'patchUrl': reverse('patch_xform', args=[domain, app.id, form.get_unique_id()]), 'allowedDataNodeReferences': [ "meta/deviceID", "meta/instanceID", "meta/username", "meta/userID", "meta/timeStart", "meta/timeEnd", "meta/location", ] + scheduler_data_nodes, 'activityUrl': reverse('ping'), 'sessionid': request.COOKIES.get('sessionid'), 'externalLinks': { 'changeSubscription': reverse("domain_subscription_view", kwargs={'domain': domain}), }, 'invalidCaseProperties': ['name'], } if toggles.APP_MANAGER_V2.enabled(request.user.username): if form.get_action_type() == 'open': core.update({ 'defaultHelpTextTemplateId': '#fd-hq-helptext-registration', 'formIconClass': 'fcc fcc-app-createform', }) elif form.get_action_type() == 'close': core.update({ 'defaultHelpTextTemplateId': '#fd-hq-helptext-close', 'formIconClass': 'fcc fcc-app-completeform', }) elif form.get_action_type() == 'update': core.update({ 'defaultHelpTextTemplateId': '#fd-hq-helptext-followup', 'formIconClass': 'fcc fcc-app-updateform', }) else: core.update({ 'defaultHelpTextTemplateId': '#fd-hq-helptext-survey', 'formIconClass': 'fa fa-file-o', }) vellum_options = { 'core': core, 'plugins': vellum_plugins, 'features': vellum_features, 'intents': { 'templates': next(app_callout_templates), }, 'javaRosa': { 'langs': app.langs, 'displayLanguage': context['lang'], }, 'uploader': { 'uploadUrls': { 'image': reverse("hqmedia_uploader_image", args=[domain, app.id]), 'audio': reverse("hqmedia_uploader_audio", args=[domain, app.id]), 'video': reverse("hqmedia_uploader_video", args=[domain, app.id]), 'text': reverse("hqmedia_uploader_text", args=[domain, app.id]), }, 'objectMap': app.get_object_map(), 'sessionid': request.COOKIES.get('sessionid'), }, } context.update({ 'vellum_options': vellum_options, 'CKEDITOR_BASEPATH': "app_manager/js/vellum/lib/ckeditor/", }) if not settings.VELLUM_DEBUG: context.update({'requirejs_url': "app_manager/js/vellum/src"}) elif settings.VELLUM_DEBUG == "dev-min": context.update({'requirejs_url': "formdesigner/_build/src"}) else: context.update({'requirejs_url': "formdesigner/src"}) context.update({ 'requirejs_args': 'version={}{}'.format( cachebuster("app_manager/js/vellum/src/main-components.js"), cachebuster("app_manager/js/vellum/src/local-deps.js")), }) template = get_app_manager_template( request.user, 'app_manager/v1/form_designer.html', 'app_manager/v2/form_designer.html', ) response = render(request, template, context) return response
def direct_ccz(request, domain): """ You must specify an app_id, and you may specify either 'version' or 'latest' latest can be one of: release: Latest starred version build: Latest version regardless of star save: Latest saved version of the application (even without a build) If 'version' and 'latest' aren't specified it will default to latest save You may also set 'include_multimedia=true' if you need multimedia. """ def error(msg, code=400): return json_response({ 'status': 'error', 'message': msg }, status_code=code) def get_app(app_id, version, latest): if version: return get_build_doc_by_version(domain, app_id, version) elif latest == 'build': return get_latest_build_doc(domain, app_id) elif latest == 'release': return get_latest_released_app_doc(domain, app_id) else: # either latest=='save' or they didn't specify return get_current_app(domain, app_id) app_id = request.GET.get('app_id', None) version = request.GET.get('version', None) latest = request.GET.get('latest', None) include_multimedia = request.GET.get('include_multimedia', 'false').lower() == 'true' # Make sure URL params make sense if not app_id: return error("You must specify `app_id` in your GET parameters") if version and latest: return error("You can't specify both 'version' and 'latest'") if latest not in ( None, 'release', 'build', 'save', ): return error("latest must be either 'release', 'build', or 'save'") if version: try: version = int(version) except ValueError: return error("'version' must be an integer") try: app = get_app(app_id, version, latest) if not app: raise ResourceNotFound() app = app if isinstance(app, Document) else wrap_app(app) except (ResourceNotFound, DocTypeError): return error("Application not found", code=404) if not app.copy_of: errors = app.validate_app() else: errors = None if errors: lang, langs = get_langs(request, app) template = get_app_manager_template( domain, 'app_manager/v1/partials/build_errors.html', 'app_manager/v2/partials/build_errors.html') error_html = render_to_string( template, { 'request': request, 'app': app, 'build_errors': errors, 'domain': domain, 'langs': langs, 'lang': lang }) return json_response( {'error_html': error_html}, status_code=400, ) app.set_media_versions(None) download = DownloadBase() errors = build_application_zip( include_multimedia_files=include_multimedia, include_index_files=True, app=app, download_id=download.download_id, compress_zip=True, filename='{}.ccz'.format(slugify(app.name)), ) if errors is not None and errors['errors']: return json_response( errors, status_code=400, ) return DownloadBase.get(download.download_id).toHttpResponse()
def form_designer(request, domain, app_id, module_id=None, form_id=None): def _form_uses_case(module, form): return module and module.case_type and form.requires_case() def _form_is_basic(form): return form.doc_type == 'Form' def _form_too_large(app, form): # form less than 0.1MB, anything larger starts to have # performance issues with fullstory return app.blobs['{}.xml'.format( form.unique_id)]['content_length'] > 102400 meta = get_meta(request) track_entered_form_builder_on_hubspot.delay(request.couch_user, request.COOKIES, meta) app = get_app(domain, app_id) module = None try: module = app.get_module(module_id) except ModuleNotFoundException: return bail(request, domain, app_id, not_found="module") try: form = module.get_form(form_id) except IndexError: return bail(request, domain, app_id, not_found="form") if form.no_vellum: messages.warning( request, _("You tried to edit this form in the Form Builder. " "However, your administrator has locked this form against editing " "in the form builder, so we have redirected you to " "the form's front page instead.")) return back_to_main(request, domain, app_id=app_id, unique_form_id=form.unique_id) include_fullstory = False vellum_plugins = ["modeliteration", "itemset", "atwho"] if (toggles.COMMTRACK.enabled(domain)): vellum_plugins.append("commtrack") if toggles.VELLUM_SAVE_TO_CASE.enabled(domain): vellum_plugins.append("saveToCase") if (_form_uses_case(module, form) and _form_is_basic(form)): vellum_plugins.append("databrowser") vellum_features = toggles.toggles_dict(username=request.user.username, domain=domain) vellum_features.update(feature_previews.previews_dict(domain)) include_fullstory = not _form_too_large(app, form) vellum_features.update({ 'group_in_field_list': app.enable_group_in_field_list, 'image_resize': app.enable_image_resize, 'markdown_in_groups': app.enable_markdown_in_groups, 'lookup_tables': domain_has_privilege(domain, privileges.LOOKUP_TABLES), 'templated_intents': domain_has_privilege(domain, privileges.TEMPLATED_INTENTS), 'custom_intents': domain_has_privilege(domain, privileges.CUSTOM_INTENTS), 'rich_text': True, }) has_schedule = (getattr(module, 'has_schedule', False) and getattr(form, 'schedule', False) and form.schedule.enabled) scheduler_data_nodes = [] if has_schedule: scheduler_data_nodes = [ SCHEDULE_CURRENT_VISIT_NUMBER, SCHEDULE_NEXT_DUE, SCHEDULE_UNSCHEDULED_VISIT, SCHEDULE_GLOBAL_NEXT_VISIT_DATE, ] scheduler_data_nodes.extend([ u"next_{}".format(f.schedule_form_id) for f in form.get_phase().get_forms() if getattr(f, 'schedule', False) and f.schedule.enabled ]) if tours.VELLUM_CASE_MANAGEMENT.is_enabled( request.user) and form.requires_case(): request.guided_tour = tours.VELLUM_CASE_MANAGEMENT.get_tour_data() vellum_base = 'corehq/apps/app_manager/static/app_manager/js/' vellum_dir = 'vellum' if isdir(join(vellum_base, 'vellum_beta')): vellum_dir = 'vellum_beta' context = get_apps_base_context(request, domain, app) context.update(locals()) context.update({ 'vellum_debug': settings.VELLUM_DEBUG, 'nav_form': form, 'vellum_style_path': 'app_manager/js/{}/style.css'.format(vellum_dir), 'vellum_ckeditor_path': 'app_manager/js/{}/lib/ckeditor/'.format(vellum_dir), 'vellum_js_path': 'app_manager/js/{}/src'.format(vellum_dir), 'vellum_main_components_path': 'app_manager/js/{}/src/main-components.js'.format(vellum_dir), 'vellum_local_deps_path': 'app_manager/js/{}/src/local-deps.js'.format(vellum_dir), 'formdesigner': True, 'multimedia_object_map': app.get_object_map(), 'sessionid': request.COOKIES.get('sessionid'), 'features': vellum_features, 'plugins': vellum_plugins, 'app_callout_templates': next(app_callout_templates), 'scheduler_data_nodes': scheduler_data_nodes, 'include_fullstory': include_fullstory, 'notifications_enabled': request.user.is_superuser, 'notify_facility': get_facility_for_form(domain, app_id, form.unique_id), }) notify_form_opened(domain, request.couch_user, app_id, form.unique_id) domain_obj = Domain.get_by_name(domain) 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') }) template = get_app_manager_template( domain, 'app_manager/v1/form_designer.html', 'app_manager/v2/form_designer.html', ) response = render(request, template, context) return response
def get_form_view_context_and_template(request, domain, form, langs, 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(u"Error in form: %s" % e) except Exception as e: logging.exception(e) form_errors.append(u"Unexpected error in form: %s" % e) 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(u"Syntax Error: %s" % e) except AppEditingError as e: form_errors.append(u"Error in application: %s" % e) except XFormValidationError: xform_validation_errored = True # showing these messages is handled by validate_form_for_build ajax pass except XFormValidationFailed: xform_validation_missing = True messages.warning(request, _("Unable to validate form due to server error.")) except XFormException as e: form_errors.append(u"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(u"Unexpected System Error: %s" % e) else: # remove upload questions (attachemnts) until MM Case Properties # are released to general public is_previewer = toggles.MM_CASE_PROPERTIES.enabled( request.user.username) 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: messages.error(request, u"Error in Case Management: %s" % e) except XFormException as e: messages.error(request, unicode(e)) except Exception as e: if settings.DEBUG: raise logging.exception(unicode(e)) messages.error(request, u"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 }) if not form.unique_id: form.get_unique_id() app.save() allow_usercase = domain_has_privilege(request.domain, privileges.USER_CASE) valid_index_names = 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 form.get_module().has_schedule case_config_options = { 'caseType': form.get_case_type(), 'moduleCaseTypes': module_case_types, 'propertiesMap': get_all_case_properties(app), 'questions': xform_questions, 'reserved_words': load_case_reserved_words(), } context = { 'nav_form': form, 'xform_languages': languages, "xform_questions": xform_questions, 'form_errors': form_errors, 'xform_validation_errored': xform_validation_errored, 'xform_validation_missing': xform_validation_missing, 'allow_cloudcare': isinstance(form, Form), 'allow_form_copy': isinstance(form, (Form, AdvancedForm)), 'allow_form_filtering': not isinstance(form, CareplanForm) and not form_has_schedule, 'allow_form_workflow': not isinstance(form, CareplanForm), '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_case_list_form': form.is_case_list_form, 'edit_name_url': reverse('edit_form_attr', args=[app.domain, app.id, form.unique_id, 'name']), 'case_xpath_pattern_matches': CASE_XPATH_PATTERN_MATCHES, 'case_xpath_substring_matches': CASE_XPATH_SUBSTRING_MATCHES, 'user_case_xpath_pattern_matches': USER_CASE_XPATH_PATTERN_MATCHES, 'user_case_xpath_substring_matches': USER_CASE_XPATH_SUBSTRING_MATCHES, 'custom_instances': [{ 'instanceId': instance.instance_id, 'instancePath': instance.instance_path } for instance in form.custom_instances], 'can_preview_form': request.couch_user.has_permission(domain, 'edit_data') } if tours.NEW_APP.is_enabled( request.user) and not toggles.APP_MANAGER_V2.enabled( request.user.username): request.guided_tour = tours.NEW_APP.get_tour_data() if context['allow_form_workflow'] and toggles.FORM_LINK_WORKFLOW.enabled( domain): module = form.get_module() def qualified_form_name(form, auto_link): module_name = trans(form.get_module().name, langs) form_name = trans(form.name, langs) star = '* ' if auto_link else ' ' return u"{}{} -> {}".format(star, module_name, form_name) modules = filter(lambda m: m.case_type == module.case_type, all_modules) if getattr(module, 'root_module_id', None) and module.root_module not in modules: modules.append(module.root_module) auto_linkable_forms = list( itertools.chain.from_iterable( list(m.get_forms()) for m in modules)) def linkable_form(candidate_form): auto_link = candidate_form in auto_linkable_forms return { 'unique_id': candidate_form.unique_id, 'name': qualified_form_name(candidate_form, auto_link), 'auto_link': auto_link } context['linkable_forms'] = [ linkable_form(candidate_form) for candidate_module in all_modules for candidate_form in candidate_module.get_forms() ] if isinstance(form, CareplanForm): case_config_options.update({ 'save_url': reverse("edit_careplan_form_actions", args=[app.domain, app.id, module.id, form.id]), 'case_preload': [{ 'key': key, 'path': path } for key, path in form.case_preload.items()], 'customCaseUpdates': [{ 'key': key, 'path': path } for key, path in form.custom_case_updates.items()], 'fixedQuestions': form.get_fixed_questions(), 'mode': form.mode, }) elif 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({ 'save_url': reverse("edit_advanced_form_actions", args=[app.domain, app.id, module.id, form.id]), 'commtrack_enabled': app.commtrack_enabled, 'commtrack_programs': all_programs + commtrack_programs(), 'module_id': module.unique_id, 'propertyDescriptions': get_case_property_description_dict(domain), }) 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 module.has_schedule: visit_scheduler_options = get_schedule_context(form) visit_scheduler_options.update({ 'questions': xform_questions, 'save_url': reverse("edit_visit_schedule", args=[app.domain, app.id, module.id, form.id]), 'schedule': form.schedule, 'phase': visit_scheduler_options['schedule_phase'], }) context.update( {'visit_scheduler_options': visit_scheduler_options}) else: case_config_options.update({ 'actions': form.actions, 'allowUsercase': allow_usercase, 'valid_index_names': valid_index_names, 'usercasePropertiesMap': get_usercase_properties(app), 'propertyDescriptions': get_case_property_description_dict(domain), 'save_url': reverse("edit_form_actions", args=[app.domain, app.id, module.id, form.id]), }) context.update({ 'show_custom_ref': toggles.APP_BUILDER_CUSTOM_PARENT_REF.enabled_for_request(request), }) context.update({'case_config_options': case_config_options}) template = get_app_manager_template( request.user, "app_manager/v1/form_view.html", "app_manager/v2/form_view.html", ) return template, context