def test_override_translations(self): translations = {'en': {'updates.check.begin': 'update?'}} self.linked_app.master = self.plain_master_app.get_id copy = self.plain_master_app.make_build() copy.save() self.addCleanup(copy.delete) self.plain_master_app.save() # increment version number copy1 = self.plain_master_app.make_build() copy1.is_released = True copy1.save() self.addCleanup(copy1.delete) self.linked_app.linked_app_translations = translations self.linked_app.save() self.assertEqual(self.linked_app.translations, {}) update_linked_app(self.linked_app, 'test_override_translations') # fetch after update to get the new version self.linked_app = LinkedApplication.get(self.linked_app._id) self.assertEqual(self.plain_master_app.translations, {}) self.assertEqual(self.linked_app.linked_app_translations, translations) self.assertEqual(self.linked_app.translations, translations)
def pull_master_app(request, domain, app_id): async_update = request.POST.get('notify') == 'on' if async_update: update_linked_app_and_notify_task.delay(domain, app_id, request.couch_user.get_id, request.couch_user.email) messages.success( request, _('Your request has been submitted. We will notify you via email once completed.' )) else: app = get_current_app(domain, app_id) try: update_linked_app(app, request.couch_user.get_id) except AppLinkError as e: messages.error(request, six.text_type(e)) return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[domain, app_id])) messages.success( request, _('Your linked application was successfully updated to the latest version.' )) track_workflow(request.couch_user.username, "Linked domain: master app pulled") return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[domain, app_id]))
def test_linked_reports_updated_for_remote(self, fake_ucr_getter): old_remote_base_url = self.domain_link.remote_base_url self.domain_link.remote_base_url = "http://my/app" self.delete_modules(self.master1) master_report, master_data_source = self._create_report_and_datasource( ) # Update app before linking report, should throw an error with self.assertRaises(AppLinkError): updated_app = update_linked_app(self.linked_app, self.master1, 'a-user-id') # Link report, then pull app fake_ucr_getter.return_value = { "report": master_report, "datasource": master_data_source, } link_info = create_linked_ucr(self.domain_link, master_report.get_id) updated_app = update_linked_app(self.linked_app, self.master1, 'a-user-id') # report config added with the linked report id updated in report config self.assertEqual(updated_app.modules[0].report_configs[0].report_id, link_info.report.get_id) # reset for other tests self.domain_link.remote_base_url = old_remote_base_url
def _inner(request, link_domain, data, master_domain=domain): clear_app_cache(request, link_domain) if data['toggles']: for slug in data['toggles'].split(","): set_toggle(slug, link_domain, True, namespace=toggles.NAMESPACE_DOMAIN) linked = data.get('linked') if linked: for module in app.modules: if isinstance(module, ReportModule): messages.error(request, _('This linked application uses mobile UCRs which ' 'are currently not supported. For this application to ' 'function correctly, you will need to remove those modules.')) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id])) master_version = get_latest_released_app_version(app.domain, app_id) if not master_version: messages.error(request, _("Creating linked app failed." " Unable to get latest released version of your app." " Make sure you have at least one released build.")) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id])) linked_app = create_linked_app(master_domain, app_id, link_domain, data['name']) try: update_linked_app(linked_app, request.couch_user.get_id) except AppLinkError as e: messages.error(request, str(e)) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id])) messages.success(request, _('Application successfully copied and linked.')) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[link_domain, linked_app.get_id])) else: extra_properties = {'name': data['name']} app_copy = import_app_util(app_id_or_source, link_domain, extra_properties) return back_to_main(request, app_copy.domain, app_id=app_copy._id)
def _create_linked_app(request, master_app, link_domain, link_app_name): master_domain = master_app.domain master_version = get_latest_released_app_version(master_domain, master_app._id) if not master_version: messages.error( request, _("Creating linked app failed." " Unable to get latest released version of your app." " Make sure you have at least one released build.")) return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[master_domain, master_app._id])) linked_app = create_linked_app(master_domain, master_app._id, link_domain, link_app_name) try: update_linked_app(linked_app, request.couch_user.get_id) except AppLinkError as e: linked_app.delete() messages.error(request, str(e)) return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[master_domain, master_app._id])) messages.success(request, _('Application successfully copied and linked.')) return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[link_domain, linked_app.get_id]))
def _inner(request, link_domain, data, master_domain=domain): clear_app_cache(request, link_domain) if data['toggles']: for slug in data['toggles'].split(","): set_toggle(slug, link_domain, True, namespace=toggles.NAMESPACE_DOMAIN) linked = data.get('linked') if linked: master_version = get_latest_released_app_version(app.domain, app_id) if not master_version: messages.error(request, _("Creating linked app failed." " Unable to get latest released version of your app." " Make sure you have at least one released build.")) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id])) linked_app = create_linked_app(master_domain, app_id, link_domain, data['name']) try: update_linked_app(linked_app, request.couch_user.get_id) except AppLinkError as e: linked_app.delete() messages.error(request, str(e)) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id])) messages.success(request, _('Application successfully copied and linked.')) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[link_domain, linked_app.get_id])) else: extra_properties = {'name': data['name']} try: app_copy = import_app_util(app_id_or_source, link_domain, extra_properties) except ReportConfigurationNotFoundError: messages.error(request, _("Copying the application failed because " "your application contains a Report Module " "that references a static UCR configuration.")) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id])) return back_to_main(request, app_copy.domain, app_id=app_copy._id)
def test_update_from_specific_build(self, *args): master_app = Application.new_app(self.domain, "Master Application") master_app.linked_whitelist = [self.linked_domain] master_app.save() self.addCleanup(master_app.delete) linked_app = LinkedApplication.new_app(self.linked_domain, "Linked Application") linked_app.master = master_app.get_id linked_app.save() self.addCleanup(linked_app.delete) master_app.add_module(Module.new_module('M1', None)) copy1 = self._make_build(master_app, True) master_app.add_module(Module.new_module('M2', None)) master_app.save() # increment version number self._make_build(master_app, True) update_linked_app(linked_app, 'test_update_from_specific_build', master_build=copy1) linked_app = LinkedApplication.get(linked_app._id) self.assertEqual(len(linked_app.modules), 1) self.assertEqual(linked_app.version, copy1.version)
def _create_linked_app(request, app_id, build_id, from_domain, to_domain, link_app_name): # Linked apps can only be created from released versions error = None if from_domain == to_domain: error = _("You may not create a linked app in the same domain as its master app.") elif build_id: from_app = Application.get(build_id) if not from_app.is_released: error = _("Make sure the version you are copying from is released.") else: from_app = get_latest_released_app(from_domain, app_id) if not from_app: error = _("Unable to get latest released version of your app." " Make sure you have at least one released build.") if error: messages.error(request, _("Creating linked app failed. {}").format(error)) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[from_domain, app_id])) linked_app = create_linked_app(from_domain, from_app.master_id, to_domain, link_app_name) try: update_linked_app(linked_app, from_app, request.couch_user.get_id) except AppLinkError as e: linked_app.delete() messages.error(request, str(e)) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[from_domain, from_app.master_id])) messages.success(request, _('Application successfully copied and linked.')) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[to_domain, linked_app.get_id]))
def _inner(request, link_domain, data, master_domain=domain): clear_app_cache(request, link_domain) if data['toggles']: for slug in data['toggles'].split(","): set_toggle(slug, link_domain, True, namespace=toggles.NAMESPACE_DOMAIN) linked = data.get('linked') if linked: master_version = get_latest_released_app_version( app.domain, app_id) if not master_version: messages.error( request, _("Creating linked app failed." " Unable to get latest released version of your app." " Make sure you have at least one released build.")) return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[domain, app_id])) linked_app = create_linked_app(master_domain, app_id, link_domain, data['name']) try: update_linked_app(linked_app, request.couch_user.get_id) except AppLinkError as e: linked_app.delete() messages.error(request, str(e)) return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[domain, app_id])) messages.success( request, _('Application successfully copied and linked.')) return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[link_domain, linked_app.get_id])) else: extra_properties = {'name': data['name']} try: app_copy = import_app_util(app_id_or_source, link_domain, extra_properties) except ReportConfigurationNotFoundError: messages.error( request, _("Copying the application failed because " "your application contains a Report Module " "that references a static UCR configuration.")) return HttpResponseRedirect( reverse_util('app_settings', params={}, args=[domain, app_id])) return back_to_main(request, app_copy.domain, app_id=app_copy._id)
def pull_master_app(request, domain, app_id): app = get_current_app(domain, app_id) try: update_linked_app(app, request.couch_user.get_id) except AppLinkError as e: messages.error(request, str(e)) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id])) messages.success(request, _('Your linked application was successfully updated to the latest version.')) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id]))
def test_override_logo(self): image_data = _get_image_data() image = CommCareImage.get_by_data(image_data) image.attach_data(image_data, original_filename='logo.png') image.add_domain(self.linked_app.domain) image.save() self.addCleanup(image.delete) image_path = "jr://file/commcare/logo/data/hq_logo_android_home.png" logo_refs = { "hq_logo_android_home": { "humanized_content_length": "45.4 KB", "icon_class": "fa fa-picture-o", "image_size": "448 X 332 Pixels", "m_id": image._id, "media_type": "Image", "path": "jr://file/commcare/logo/data/hq_logo_android_home.png", "uid": "3b79a76a067baf6a23a0b6978b2fb352", "updated": False, "url": "/hq/multimedia/file/CommCareImage/e3c45dd61c5593fdc5d985f0b99f6199/" }, } self.linked_app.master = self.plain_master_app.get_id copy = self.plain_master_app.make_build() copy.save() self.addCleanup(copy.delete) self.plain_master_app.save() # increment version number copy1 = self.plain_master_app.make_build() copy1.is_released = True copy1.save() self.addCleanup(copy1.delete) self.linked_app.version = 1 self.linked_app.linked_app_logo_refs = logo_refs self.linked_app.create_mapping(image, image_path, save=False) self.linked_app.save() self.assertEqual(self.linked_app.logo_refs, {}) update_linked_app(self.linked_app, 'test_override_logos') # fetch after update to get the new version self.linked_app = LinkedApplication.get(self.linked_app._id) self.assertEqual(self.plain_master_app.logo_refs, {}) self.assertEqual(self.linked_app.linked_app_logo_refs, logo_refs) self.assertEqual(self.linked_app.logo_refs, logo_refs) # cleanup the linked app logo properties self.linked_app.linked_app_logo_refs = {} self.linked_app.save()
def handle(self, master_id, linked_id, url_base, domain, username, api_key, **options): remote_details = RemoteLinkDetails( url_base, username, api_key, ) linked_app = LinkedApplication.get(linked_id) link_app(linked_app, domain, master_id, remote_details) update_linked_app(linked_app, master_id, 'system')
def test_linked_reports_not_updated_for_remote( self, get_report_configs_for_domain): old_remote_base_url = self.domain_link.remote_base_url self.domain_link.remote_base_url = "http://my/app" self.domain_link.save() update_linked_app(self.linked_app, self.master1, 'TestLinkedApps user') get_report_configs_for_domain.assert_not_called() # reset for other tests self.domain_link.remote_base_url = old_remote_base_url self.domain_link.save()
def handle(self, master_id, linked_id, **options): print("Linking apps") master_app = Application.get(master_id) master_version = get_latest_released_app_version(master_app.domain, master_id) if not master_version: raise CommandError( "Creating linked app failed." " Unable to get latest released version of your app." " Make sure you have at least one released build." ) linked_app = LinkedApplication.get(linked_id) link_app(linked_app, master_app.domain, master_id) update_linked_app(linked_app, 'system')
def pull_master_app(request, domain, app_id): async_update = request.POST.get('notify') == 'on' if async_update: update_linked_app_and_notify_task.delay(domain, app_id, request.couch_user.get_id, request.couch_user.email) messages.success(request, _('Your request has been submitted. We will notify you via email once completed.')) else: app = get_current_app(domain, app_id) try: update_linked_app(app, request.couch_user.get_id) except AppLinkError as e: messages.error(request, six.text_type(e)) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id])) messages.success(request, _('Your linked application was successfully updated to the latest version.')) track_workflow(request.couch_user.username, "Linked domain: master app pulled") return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[domain, app_id]))
def test_linked_reports_updated(self): # add a report on the master app master_data_source = get_sample_data_source() master_data_source.domain = self.domain master_data_source.save() master_report = get_sample_report_config() master_report.config_id = master_data_source.get_id master_report.domain = self.domain master_report.save() master_reports_module = self.master1.add_module( ReportModule.new_module('Reports', None)) master_reports_module.report_configs = [ ReportAppConfig(report_id=master_report.get_id, header={'en': 'CommBugz'}), ] # link report on master app to linked domain link_info = create_linked_ucr(self.domain_link, master_report.get_id) updated_app = update_linked_app(self.linked_app, self.master1, 'a-user-id') # report config added with the linked report id updated in report config self.assertEqual(updated_app.modules[0].report_configs[0].report_id, link_info.report.get_id)
def _release_app(self, domain_link, model, user, build_and_release=False): if toggles.MULTI_MASTER_LINKED_DOMAINS.enabled( domain_link.linked_domain): return self._error_tuple(_("Multi master flag is in use")) app_id = model['detail']['app_id'] found = False error_prefix = "" try: for linked_app in get_apps_in_domain(domain_link.linked_domain, include_remote=False): if is_linked_app( linked_app) and linked_app.family_id == app_id: found = True app = update_linked_app(linked_app, app_id, user.user_id) if not found: return self._error_tuple(_("Could not find app")) if build_and_release: error_prefix = _("Updated app but did not build or release: ") build = app.make_build() build.is_released = True build.save(increment_version=False) except Exception as e: # intentionally broad return self._error_tuple(error_prefix + str(e))
def _create_linked_app(request, master_app, link_domain, link_app_name): master_domain = master_app.domain master_version = get_latest_released_app_version(master_domain, master_app._id) if not master_version: messages.error(request, _("Creating linked app failed." " Unable to get latest released version of your app." " Make sure you have at least one released build.")) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[master_domain, master_app._id])) linked_app = create_linked_app(master_domain, master_app._id, link_domain, link_app_name) try: update_linked_app(linked_app, request.couch_user.get_id) except AppLinkError as e: linked_app.delete() messages.error(request, str(e)) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[master_domain, master_app._id])) messages.success(request, _('Application successfully copied and linked.')) return HttpResponseRedirect(reverse_util('app_settings', params={}, args=[link_domain, linked_app.get_id]))
def testConvertToApplication(self): factory = AppFactory(build_version='2.40.0') factory.new_basic_module('register', 'case', with_form=False) factory.app.save() build = factory.app.make_build() build.is_released = True build.save() linked_app = LinkedApplication() linked_app.domain = 'other-domain' linked_app.save() link_app(linked_app, factory.app.domain, factory.app.id) update_linked_app(linked_app, factory.app.id, 'system') unlinked_doc = linked_app.convert_to_application().to_json() self.assertEqual(unlinked_doc['doc_type'], 'Application') self.assertFalse(hasattr(unlinked_doc, 'linked_app_attrs')) linked_app.delete()
def testConvertToApplication(self): factory = AppFactory(build_version='2.40.0') m0, f0 = factory.new_basic_module('register', 'case') f0.source = get_simple_form(xmlns=f0.unique_id) factory.app.save() self.addCleanup(factory.app.delete) build = factory.app.make_build() build.is_released = True build.save() self.addCleanup(build.delete) linked_app = LinkedApplication() linked_app.domain = 'other-domain' linked_app.save() self.addCleanup(linked_app.delete) link_app(linked_app, factory.app.domain, factory.app.id) update_linked_app(linked_app, factory.app.id, 'system') unlinked_doc = linked_app.convert_to_application().to_json() self.assertEqual(unlinked_doc['doc_type'], 'Application') self.assertFalse(hasattr(unlinked_doc, 'linked_app_attrs'))
def test_update_from_specific_build(self, *args): factory = AppFactory(self.domain, "Upstream Application") m0, f0 = factory.new_basic_module("M1", None) f0.source = get_simple_form() master_app = factory.app master_app.save() self.addCleanup(master_app.delete) linked_app = LinkedApplication.new_app(self.linked_domain, "Linked Application") linked_app.save() self.addCleanup(linked_app.delete) copy1 = self._make_build(master_app, True) m1, f1 = factory.new_basic_module("M2", None) f1.source = get_simple_form() master_app.save() # increment version number self._make_build(master_app, True) update_linked_app(linked_app, copy1, 'test_update_from_specific_build') linked_app = LinkedApplication.get(linked_app._id) self.assertEqual(len(linked_app.modules), 1) self.assertEqual(linked_app.version, copy1.version)
def test_linked_reports_updated(self): # add a report on the master app self.delete_modules(self.master1) master_report, master_data_source = self._create_report_and_datasource( ) # link report on master app to linked domain link_info = create_linked_ucr(self.domain_link, master_report.get_id) updated_app = update_linked_app(self.linked_app, self.master1, 'a-user-id') # report config added with the linked report id updated in report config self.assertEqual(updated_app.modules[0].report_configs[0].report_id, link_info.report.get_id)
def _pull_linked_app(self, upstream_app_id): update_linked_app(self.linked_app, upstream_app_id, 'TestLinkedApps user') self.linked_app = LinkedApplication.get(self.linked_app._id)
def _pull_linked_app(self): update_linked_app(self.linked_app, 'TestLinkedApps user') self.linked_app = LinkedApplication.get(self.linked_app._id)
def push_models(master_domain, models, linked_domains, build_apps, username): domain_links_by_linked_domain = { link.linked_domain: link for link in get_linked_domains(master_domain) } user = CouchUser.get_by_username(username) errors_by_domain = defaultdict(list) successes_by_domain = defaultdict(list) for linked_domain in linked_domains: if linked_domain not in domain_links_by_linked_domain: errors_by_domain[linked_domain].append( _("Project space {} is no longer linked to {}. No content " "was released to it.").format(master_domain, linked_domain)) continue domain_link = domain_links_by_linked_domain[linked_domain] for model in models: try: found = False updated_app = False built_app = False if model['type'] == MODEL_APP: app_id = model['detail']['app_id'] for linked_app in get_apps_in_domain(linked_domain, include_remote=False): if is_linked_app( linked_app) and linked_app.family_id == app_id: found = True if toggles.MULTI_MASTER_LINKED_DOMAINS.enabled( linked_domain): errors_by_domain[linked_domain].append( textwrap.dedent( _(""" Could not update {} because multi master flag is in use """.strip()).format(model['name']))) continue app = update_linked_app(linked_app, app_id, user.user_id) updated_app = True if build_apps: build = app.make_build() build.is_released = True build.save(increment_version=False) built_app = True elif model['type'] == MODEL_REPORT: report_id = model['detail']['report_id'] for linked_report in get_report_configs_for_domain( linked_domain): if linked_report.report_meta.master_id == report_id: found = True update_linked_ucr(domain_link, linked_report.get_id) elif (model['type'] == MODEL_CASE_SEARCH and not toggles.SYNC_SEARCH_CASE_CLAIM.enabled(linked_domain) ): errors_by_domain[linked_domain].append( textwrap.dedent( _(""" Could not update {} because case claim flag is not on """.strip()).format(model['name']))) continue else: found = True update_model_type(domain_link, model['type'], model_detail=model['detail']) domain_link.update_last_pull(model['type'], user._id, model_details=model['detail']) if found: successes_by_domain[linked_domain].append( _("{} was updated").format(model['name'])) else: errors_by_domain[linked_domain].append( _("Could not find {}").format(model['name'])) except Exception as e: # intentionally broad if model[ 'type'] == MODEL_APP and updated_app and build_apps and not built_app: # Updating an app can be a 2-step process, make it clear which one failed errors_by_domain[linked_domain].append( textwrap.dedent( _(""" Updated {} but could not make and release build: {} """.strip()).format(model['name'], str(e)))) else: errors_by_domain[linked_domain].append( textwrap.dedent( _(""" Could not update {}: {} """.strip()).format(model['name'], str(e)))) notify_exception( None, "Exception pushing linked domains: {}".format(e)) subject = _("Linked project release complete.") if errors_by_domain: subject += _(" Errors occurred.") error_domain_count = len(errors_by_domain) success_domain_count = len(linked_domains) - error_domain_count message = _(""" Release complete. {} project(s) succeeded. {} The following content was released: {} The following linked project spaces received content: """).format( success_domain_count, _("{} project(s) encountered errors.").format(error_domain_count) if error_domain_count else "", "\n".join(["- " + m['name'] for m in models])) for linked_domain in linked_domains: if linked_domain not in errors_by_domain: message += _("\n- {} updated successfully").format(linked_domain) else: message += _("\n- {} encountered errors:").format(linked_domain) for msg in errors_by_domain[linked_domain] + successes_by_domain[ linked_domain]: message += "\n - " + msg send_mail_async.delay(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email or user.username])