def form_source(request, domain, app_id, form_unique_id): app = get_app(domain, app_id) try: form = app.get_form(form_unique_id) except FormNotFoundException: return bail(request, domain, app_id, not_found="form") try: module = form.get_module() except AttributeError: return bail(request, domain, app_id, not_found="module") return _get_form_designer_view(request, domain, app, module, form)
def form_source_legacy(request, domain, app_id, module_id=None, form_id=None): """ This view has been kept around to not break any documentation on example apps and partner-distributed documentation on existing apps. PLEASE DO NOT DELETE. """ app = get_app(domain, app_id) 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") return _get_form_designer_view(request, domain, app, module, form)
def delete_module(request, domain, app_id, module_unique_id): "Deletes a module from an app" app = get_app(domain, app_id) try: record = app.delete_module(module_unique_id) except ModuleNotFoundException: return bail(request, domain, app_id) if record is not None: messages.success( request, 'You have deleted a module. <a href="%s" class="post-link">Undo</a>' % reverse('undo_delete_module', args=[domain, record.get_id]), extra_tags='html') app.save() return back_to_main(request, domain, app_id=app_id)
def delete_module(request, domain, app_id, module_unique_id): "Deletes a module from an app" app = get_app(domain, app_id) try: record = app.delete_module(module_unique_id) except ModuleNotFoundException: return bail(request, domain, app_id) if record is not None: messages.success( request, 'You have deleted a module. <a href="%s" class="post-link">Undo</a>' % reverse( 'undo_delete_module', args=[domain, record.get_id] ), extra_tags='html' ) app.save() return back_to_main(request, domain, app_id=app_id)
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 view_generic(request, domain, app_id=None, module_id=None, form_id=None, copy_app_form=None): """ 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) if app and app.application_version == APP_V1: _assert = soft_assert() _assert(False, 'App version 1.0', {'domain': domain, 'app_id': app_id}) return render(request, 'app_manager/v1/no_longer_supported.html', { 'domain': domain, 'app': app, }) context = get_apps_base_context(request, domain, app) if app and app.copy_of: # don't fail hard. return HttpResponseRedirect( reverse("corehq.apps.app_manager.views.view_app", args=[domain, app.copy_of])) # 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({ 'case_properties': get_all_case_properties(app), 'usercase_properties': get_usercase_properties(app), }) context.update(form_context) elif module: template = get_module_template(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: template = "app_manager/v1/app_view.html" context.update(get_app_view_context(request, app)) 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_id, export_zipped_apps_enabled=toggle_enabled) context.update({ 'domain_names': domain_names, }) context.update({ 'copy_app_form': copy_app_form, }) 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 context.update({ "sessionid": request.COOKIES.get('sessionid'), 'uploaders': [ MultimediaLogoUploadController( slug, reverse( ProcessLogoFileUploadView.name, args=[domain, app_id, slug], )) for slug in uploader_slugs ], "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) }, }) 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 form_designer(request, domain, app_id, module_id=None, form_id=None, is_user_registration=False): 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 if is_user_registration: form = app.get_user_registration() else: 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) vellum_plugins = ["modeliteration", "itemset"] if toggles.VELLUM_TRANSACTION_QUESTION_TYPES.enabled(domain): vellum_plugins.append("commtrack") if toggles.VELLUM_SAVE_TO_CASE.enabled(domain): vellum_plugins.append("saveToCase") if toggles.VELLUM_EXPERIMENTAL_UI.enabled(domain): vellum_plugins.append("databrowser") vellum_features = toggles.toggles_dict(username=request.user.username, domain=domain) 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), }) 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 ]) context = get_apps_base_context(request, domain, app) context.update(locals()) context.update({ 'vellum_debug': settings.VELLUM_DEBUG, 'nav_form': form if not is_user_registration else '', '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, }) return render(request, 'app_manager/form_designer.html', context)
def view_generic(request, domain, app_id, module_id=None, form_id=None, copy_app_form=None, release_manager=False, module_unique_id=None, form_unique_id=None): """ This is the main view for the app. All other views redirect to here. """ if form_id and not module_id and module_unique_id is None: return bail(request, domain, app_id) app = get_app(domain, app_id) module = form = None if module_id: try: module = app.get_module(module_id) except ModuleNotFoundException: raise Http404() if not module.unique_id: module.get_or_create_unique_id() app.save() elif module_unique_id: try: module = app.get_module_by_unique_id(module_unique_id) except ModuleNotFoundException: raise Http404() module_id = module.id if form_id and module is not None: try: form = module.get_form(form_id) except IndexError: raise Http404() elif form_unique_id: try: form = app.get_form(form_unique_id) except FormNotFoundException: raise Http404() form_id = form.id if form is not None and module is None: # this is the case where only the form_unique_id is given module = form.get_module() module_id = module.id # Application states that should no longer exist if app.application_version == APP_V1: _assert = soft_assert() _assert(False, 'App version 1.0', {'domain': domain, 'app_id': app_id}) return render(request, "app_manager/no_longer_supported.html", { 'domain': domain, 'app': app, }) if not app.vellum_case_management and not app.is_remote_app(): # Soft assert but then continue rendering; template will contain a user-facing warning _assert = soft_assert(['jschweers' + '@' + 'dimagi.com']) _assert(False, 'vellum_case_management=False', { 'domain': domain, 'app_id': app_id }) if (form is not None and "usercase_preload" in getattr(form, "actions", {}) and form.actions.usercase_preload.preload): _assert = soft_assert(['dmiller' + '@' + 'dimagi.com']) _assert( False, 'User property easy refs + old-style config = bad', { 'domain': domain, 'app_id': app_id, 'module_id': module_id, 'module_unique_id': module_unique_id, 'form_id': form_id, 'form_unique_id': form_unique_id, }) context = get_apps_base_context(request, domain, app) if app.copy_of: # redirect to "main" app rather than specific build return HttpResponseRedirect( reverse("view_app", args=[domain, app.copy_of])) context.update({ 'module': module, 'form': form, }) lang = context['lang'] if not module and hasattr(app, 'translations'): context.update({"translations": app.translations.get(lang, {})}) if not app.is_remote_app(): context.update({ 'add_ons': add_ons.get_dict(request, app, module, form), 'add_ons_privileges': add_ons.get_privileges_dict(request), 'add_ons_layout': add_ons.get_layout(request), }) if form: template, form_context = get_form_view_context_and_template( request, domain, form, context['langs'], current_lang=lang) context.update(form_context) elif module: template = get_module_template(request.user, module) # make sure all modules have unique ids app.ensure_module_unique_ids(should_save=True) module_context = get_module_view_context(request, app, module, lang) context.update(module_context) else: context.update(get_app_view_context(request, app)) template = 'app_manager/app_view_settings.html' if release_manager: template = 'app_manager/app_view_release_manager.html' if release_manager: context.update(get_releases_context(request, domain, app_id)) context.update({ 'is_app_settings_page': not release_manager, }) # update multimedia context for forms and modules. menu_host = form or module if menu_host: default_file_name = 'module%s' % module_id if form: default_file_name = '%s_form%s' % (default_file_name, form_id) specific_media = [{ 'menu_refs': app.get_menu_media(module, form=form, form_index=form_id, to_language=lang), 'default_file_name': '{name}_{lang}'.format(name=default_file_name, lang=lang), }] if not form and module and not isinstance( module, ReportModule) and module.uses_media(): def _make_name(suffix): return "{default_name}_{suffix}_{lang}".format( default_name=default_file_name, suffix=suffix, lang=lang, ) specific_media.append({ 'menu_refs': app.get_case_list_form_media(module, to_language=lang), 'default_file_name': _make_name('case_list_form'), 'qualifier': 'case_list_form_', }) specific_media.append({ 'menu_refs': app.get_case_list_menu_item_media(module, to_language=lang), 'default_file_name': _make_name('case_list_menu_item'), 'qualifier': 'case_list-menu_item_', }) if (toggles.CASE_LIST_LOOKUP.enabled(request.user.username) or toggles.CASE_LIST_LOOKUP.enabled(app.domain) or toggles.BIOMETRIC_INTEGRATION.enabled(app.domain)): specific_media.append({ 'menu_refs': app.get_case_list_lookup_image(module), 'default_file_name': '{}_case_list_lookup'.format(default_file_name), 'qualifier': 'case-list-lookupcase', }) if hasattr(module, 'product_details'): specific_media.append({ 'menu_refs': app.get_case_list_lookup_image(module, type='product'), 'default_file_name': '{}_product_list_lookup'.format(default_file_name), 'qualifier': 'case-list-lookupproduct', }) uploaders = { 'icon': MultimediaImageUploadController( "hqimage", reverse(ProcessImageFileUploadView.urlname, args=[app.domain, app.get_id])), 'audio': MultimediaAudioUploadController( "hqaudio", reverse(ProcessAudioFileUploadView.urlname, args=[app.domain, app.get_id])), } multimedia_map = app.multimedia_map if form or module: multimedia_map = (form or module).get_relevant_multimedia_map(app) context.update({ 'multimedia': { "object_map": app.get_object_map(multimedia_map=multimedia_map), 'upload_managers': uploaders, 'upload_managers_js': {type: u.js_options for type, u in uploaders.items()}, } }) context['module_icon'] = None if toggles.CUSTOM_ICON_BADGES.enabled(domain): context[ 'module_icon'] = module.custom_icon if module.custom_icon else CustomIcon( ) context['nav_menu_media_specifics'] = specific_media error = request.GET.get('error', '') context.update({ 'error': error, 'app': app, }) # Pass form for Copy Application to template domain_names = { d.name for d in Domain.active_for_user(request.couch_user) if not (is_linked_domain(request.domain) and get_domain_master_link( request.domain).master_domain == d.name) } domain_names.add(request.domain) if copy_app_form is None: copy_app_form = CopyApplicationForm(domain, app) context.update({ 'domain_names': sorted(domain_names), }) linked_domains_enabled = toggles.LINKED_DOMAINS.enabled(domain) context.update({ 'copy_app_form': copy_app_form, 'linked_domains_enabled': linked_domains_enabled, }) context['latest_commcare_version'] = get_commcare_versions( request.user)[-1] if not is_remote_app(app) and has_privilege( request, privileges.COMMCARE_LOGO_UPLOADER): uploader_slugs = list(ANDROID_LOGO_PROPERTY_MAPPING.keys()) from corehq.apps.hqmedia.controller import MultimediaLogoUploadController from corehq.apps.hqmedia.views import ProcessLogoFileUploadView uploaders = [ MultimediaLogoUploadController( slug, reverse( ProcessLogoFileUploadView.urlname, args=[domain, app_id, slug], )) for slug in uploader_slugs ] context.update({ "sessionid": request.COOKIES.get('sessionid'), "uploaders": uploaders, "uploaders_js": [u.js_options for u in uploaders], "refs": { slug: ApplicationMediaReference( app.logo_refs.get(slug, {}).get("path", slug), media_class=CommCareImage, ).as_dict() for slug in uploader_slugs }, "media_info": { slug: app.logo_refs.get(slug) for slug in uploader_slugs if app.logo_refs.get(slug) }, }) context.update({ 'show_live_preview': should_show_preview_app(request, app, request.couch_user.username), 'can_preview_form': request.couch_user.has_permission(domain, 'edit_data') }) confirm = request.session.pop('CONFIRM', False) context.update({'confirm': confirm}) response = render(request, template, context) set_lang_cookie(response, lang) return response
def view_generic(request, domain, app_id=None, module_id=None, form_id=None, copy_app_form=None, release_manager=False, module_unique_id=None, form_unique_id=None): """ This is the main view for the app. All other views redirect to here. """ if form_id and not module_id and module_unique_id is None: return bail(request, domain, app_id) app = 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() elif module_unique_id: try: module = app.get_module_by_unique_id(module_unique_id) except ModuleNotFoundException: raise Http404() module_id = module.id if form_id and module is not None: try: form = module.get_form(form_id) except IndexError: raise Http404() elif form_unique_id: try: form = app.get_form(form_unique_id) except FormNotFoundException: raise Http404() form_id = form.id if form is not None and module is None: # this is the case where only the form_unique_id is given module = form.get_module() module_id = module.id except (ModuleNotFoundException, FormNotFoundException): 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}) return render(request, "app_manager/no_longer_supported.html", { 'domain': domain, 'app': app, }) if not app.vellum_case_management and not app.is_remote_app(): # Soft assert but then continue rendering; template will contain a user-facing warning _assert = soft_assert(['jschweers' + '@' + 'dimagi.com']) _assert(False, 'vellum_case_management=False', {'domain': domain, 'app_id': app_id}) if (form is not None and "usercase_preload" in getattr(form, "actions", {}) and form.actions.usercase_preload.preload): _assert = soft_assert(['dmiller' + '@' + 'dimagi.com']) _assert(False, 'User property easy refs + old-style config = bad', { 'domain': domain, 'app_id': app_id, 'module_id': module_id, 'module_unique_id': module_unique_id, 'form_id': form_id, 'form_unique_id': form_unique_id, }) context = get_apps_base_context(request, domain, app) if app and app.copy_of: # redirect to "main" app rather than specific build return HttpResponseRedirect(reverse( "view_app", args=[domain, app.copy_of] )) context.update({ 'module': module, 'form': form, }) lang = context['lang'] if app and not module and hasattr(app, 'translations'): context.update({"translations": app.translations.get(lang, {})}) if app and not app.is_remote_app(): context.update({ 'add_ons': add_ons.get_dict(request, app, module, form), 'add_ons_layout': add_ons.get_layout(request), }) if form: template, form_context = get_form_view_context_and_template( request, domain, form, context['langs'], current_lang=lang ) context.update(form_context) elif module: template = get_module_template(request.user, module) # make sure all modules have unique ids app.ensure_module_unique_ids(should_save=True) module_context = get_module_view_context(app, module, lang) context.update(module_context) elif app: context.update(get_app_view_context(request, app)) template = 'app_manager/app_view_settings.html' if release_manager: template = 'app_manager/app_view_release_manager.html' if release_manager: context.update(get_releases_context(request, domain, app_id)) context.update({ 'is_app_settings_page': not release_manager, }) else: from corehq.apps.dashboard.views import DomainDashboardView return HttpResponseRedirect(reverse(DomainDashboardView.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: default_file_name = '%s_form%s' % (default_file_name, form_id) specific_media = [{ '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 not form and module and not isinstance(module, ReportModule) and module.uses_media(): def _make_name(suffix): return "{default_name}_{suffix}_{lang}".format( default_name=default_file_name, suffix=suffix, lang=lang, ) specific_media.append({ 'menu_refs': app.get_case_list_form_media(module, module_id, to_language=lang), 'default_file_name': _make_name('case_list_form'), 'qualifier': 'case_list_form_', }) specific_media.append({ 'menu_refs': app.get_case_list_menu_item_media(module, module_id, to_language=lang), 'default_file_name': _make_name('case_list_menu_item'), 'qualifier': 'case_list-menu_item_', }) if (toggles.CASE_LIST_LOOKUP.enabled(request.user.username) or toggles.CASE_LIST_LOOKUP.enabled(app.domain)): specific_media.append({ 'menu_refs': app.get_case_list_lookup_image(module, module_id), 'default_file_name': '{}_case_list_lookup'.format(default_file_name), 'qualifier': 'case-list-lookupcase', }) if hasattr(module, 'product_details'): specific_media.append({ 'menu_refs': app.get_case_list_lookup_image(module, module_id, type='product'), 'default_file_name': '{}_product_list_lookup'.format(default_file_name), 'qualifier': 'case-list-lookupproduct', }) uploaders = { 'icon': MultimediaImageUploadController( "hqimage", reverse(ProcessImageFileUploadView.urlname, args=[app.domain, app.get_id]) ), 'audio': MultimediaAudioUploadController( "hqaudio", reverse(ProcessAudioFileUploadView.urlname, args=[app.domain, app.get_id]) ), } context.update({ 'multimedia': { "object_map": app.get_object_map(), 'upload_managers': uploaders, 'upload_managers_js': {type: u.js_options for type, u in six.iteritems(uploaders)}, } }) context['module_icon'] = None if toggles.CUSTOM_ICON_BADGES.enabled(domain): context['module_icon'] = module.custom_icon if module.custom_icon else CustomIcon() try: context['multimedia']['references'] = app.get_references() except ReportConfigurationNotFoundError: pass context['nav_menu_media_specifics'] = specific_media error = request.GET.get('error', '') context.update({ 'error': error, 'app': app, }) # Pass form for Copy Application to template domain_names = [ d.name for d in Domain.active_for_user(request.couch_user) if not (is_linked_domain(request.domain) and get_domain_master_link(request.domain).master_domain == d.name) ] domain_names.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_domains_enabled = toggles.LINKED_DOMAINS.enabled(domain) context.update({ 'copy_app_form': copy_app_form, 'linked_domains_enabled': linked_domains_enabled, }) context['latest_commcare_version'] = get_commcare_versions(request.user)[-1] if (app and app.doc_type in ('Application', 'LinkedApplication') and has_privilege(request, privileges.COMMCARE_LOGO_UPLOADER)): uploader_slugs = list(ANDROID_LOGO_PROPERTY_MAPPING.keys()) from corehq.apps.hqmedia.controller import MultimediaLogoUploadController from corehq.apps.hqmedia.views import ProcessLogoFileUploadView uploaders = [ MultimediaLogoUploadController( slug, reverse( ProcessLogoFileUploadView.urlname, args=[domain, app_id, slug], ) ) for slug in uploader_slugs ] context.update({ "sessionid": request.COOKIES.get('sessionid'), "uploaders": uploaders, "uploaders_js": [u.js_options for u in uploaders], "refs": { slug: ApplicationMediaReference( app.logo_refs.get(slug, {}).get("path", slug), media_class=CommCareImage, 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) }, }) 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') }) confirm = request.session.pop('CONFIRM', False) context.update({'confirm': confirm}) 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() 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 view_generic(request, domain, app_id=None, module_id=None, form_id=None, is_user_registration=False, copy_app_form=None): """ 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 is_user_registration: if not app.show_user_registration: raise Http404() form = app.get_user_registration() 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) context = get_apps_base_context(request, domain, app) if app and app.copy_of: # don't fail hard. return HttpResponseRedirect(reverse( "corehq.apps.app_manager.views.view_app", args=[domain, app.copy_of] )) # 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'], is_user_registration ) context.update({ 'case_properties': get_all_case_properties(app), 'usercase_properties': get_usercase_properties(app), }) context.update(form_context) elif module: template = get_module_template(module) # make sure all modules have unique ids app.ensure_module_unique_ids(should_save=True) module_context = get_module_view_context(app, module) context.update(module_context) elif app: template = "app_manager/app_view.html" context.update(get_app_view_context(request, app)) else: from corehq.apps.dashboard.views import NewUserDashboardView from corehq.apps.style.utils import set_bootstrap_version3 from crispy_forms.utils import set_template_pack set_bootstrap_version3() set_template_pack('bootstrap3') template = NewUserDashboardView.template_name context.update({'templates': NewUserDashboardView.templates(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': { "references": app.get_references(), "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]) ), }, } }) 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.user)] domain_names.sort() context.update({ 'copy_app_form': copy_app_form if copy_app_form is not None else CopyApplicationForm(app_id), 'domain_names': domain_names, }) 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 context.update({ "sessionid": request.COOKIES.get('sessionid'), 'uploaders': [ MultimediaLogoUploadController( slug, reverse( ProcessLogoFileUploadView.name, args=[domain, app_id, slug], ) ) for slug in uploader_slugs ], "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) }, }) 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, '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) live_preview_ab = ab_tests.ABTest(ab_tests.LIVE_PREVIEW, request) domain_obj = Domain.get_by_name(domain) context.update({ 'live_preview_ab': live_preview_ab.context, 'is_onboarding_domain': domain_obj.is_onboarding_domain, 'show_live_preview': ( toggles.PREVIEW_APP.enabled(domain) or toggles.PREVIEW_APP.enabled(request.couch_user.username) or (domain_obj.is_onboarding_domain and live_preview_ab.version == ab_tests.LIVE_PREVIEW_ENABLED) ) }) response = render(request, 'app_manager/v1/form_designer.html', context) live_preview_ab.update_response(response) return response
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}) return render(request, 'app_manager/v1/no_longer_supported.html', { 'domain': domain, 'app': app, }) if not app.vellum_case_management: # 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}) 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({ 'case_properties': get_all_case_properties(app), 'usercase_properties': get_usercase_properties(app), }) context.update(form_context) elif module: template = get_module_template(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: # todo APP MANAGER V2 update template here # if release_manager: template = "app_manager/v1/app_view.html" context.update(get_app_view_context(request, app)) else: from corehq.apps.dashboard.views import NewUserDashboardView if toggles.APP_MANAGER_V2.enabled(domain): context.update(NewUserDashboardView.get_page_context(domain)) else: 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_id, export_zipped_apps_enabled=toggle_enabled) context.update({ 'domain_names': domain_names, }) context.update({ 'copy_app_form': copy_app_form, }) 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 context.update({ "sessionid": request.COOKIES.get('sessionid'), 'uploaders': [ MultimediaLogoUploadController( slug, reverse( ProcessLogoFileUploadView.name, args=[domain, app_id, slug], ) ) for slug in uploader_slugs ], "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) }, }) live_preview_ab = ab_tests.ABTest(ab_tests.LIVE_PREVIEW, request) domain_obj = Domain.get_by_name(domain) context.update({ 'live_preview_ab': live_preview_ab.context, 'is_onboarding_domain': domain_obj.is_onboarding_domain, 'show_live_preview': ( toggles.PREVIEW_APP.enabled(domain) or toggles.PREVIEW_APP.enabled(request.couch_user.username) or (domain_obj.is_onboarding_domain and live_preview_ab.version == ab_tests.LIVE_PREVIEW_ENABLED) ) }) response = render(request, template, context) live_preview_ab.update_response(response) response.set_cookie('lang', encode_if_unicode(lang)) return response