def test_get_built_app_ids_for_app_id(self): app_ids = get_built_app_ids_for_app_id(self.domain, self.apps[0].get_id) self.assertEqual(len(app_ids), 2) app_ids = get_built_app_ids_for_app_id(self.domain, self.apps[0].get_id, self.first_saved_version) self.assertEqual(len(app_ids), 1) self.assertEqual(self.decoy_apps[1].get_id, app_ids[0])
def testPruneAutoGeneratedBuilds(self, mock): # Build #1, manually generated app = import_app(self._yesno_source, self.domain) for module in app.modules: module.get_or_create_unique_id() app.save() build1 = app.make_build() build1.save() self.assertFalse(build1.is_auto_generated) # Build #2, auto-generated app.save() make_async_build(app, 'someone') build_ids = get_built_app_ids_for_app_id(app.domain, app.id) self.assertEqual(len(build_ids), 2) self.assertEqual(build_ids[0], build1.id) build2 = get_app(app.domain, build_ids[1]) self.assertTrue(build2.is_auto_generated) # First prune: delete nothing because the auto build is the most recent prune_auto_generated_builds(self.domain, app.id) self.assertEqual(len(get_built_app_ids_for_app_id(app.domain, app.id)), 2) # Build #3, manually generated app.save() build3 = app.make_build() build3.save() # Release the auto-generated build and prune again, should still delete nothing build2.is_released = True build2.save() prune_auto_generated_builds(self.domain, app.id) self.assertEqual(len(get_built_app_ids_for_app_id(app.domain, app.id)), 3) # Un-release the auto-generated build and prune again, which should delete it build2.is_released = False build2.save() prune_auto_generated_builds(self.domain, app.id) build_ids = get_built_app_ids_for_app_id(app.domain, app.id) self.assertEqual(len(build_ids), 2) self.assertNotIn(build2.id, build_ids)
def generate_schema_from_builds(domain, app_id, form_xmlns, force_rebuild=False): """Builds a schema from Application builds for a given identifier :param domain: The domain that the export belongs to :param app_id: The app_id that the export belongs to :param unique_form_id: The unique identifier of the item being exported :returns: Returns a FormExportDataSchema instance """ original_id, original_rev = None, None current_xform_schema = get_latest_form_export_schema(domain, app_id, form_xmlns) if current_xform_schema and not force_rebuild: original_id, original_rev = current_xform_schema._id, current_xform_schema._rev else: current_xform_schema = FormExportDataSchema() app_build_ids = get_built_app_ids_for_app_id( domain, app_id, current_xform_schema.last_app_versions.get(app_id) ) for app_doc in iter_docs(Application.get_db(), app_build_ids): app = Application.wrap(app_doc) xform = app.get_form_by_xmlns(form_xmlns, log_missing=False) if not xform: continue xform = xform.wrapped_xform() xform_schema = FormExportDataSchema._generate_schema_from_xform( xform, app.langs, app.copy_of, app.version, ) current_xform_schema = FormExportDataSchema._merge_schemas(current_xform_schema, xform_schema) current_xform_schema.record_update(app.copy_of, app.version) if original_id and original_rev: current_xform_schema._id = original_id current_xform_schema._rev = original_rev current_xform_schema.domain = domain current_xform_schema.app_id = app_id current_xform_schema.xmlns = form_xmlns current_xform_schema.save() return current_xform_schema
def generate_schema_from_builds(domain, app_id, unique_form_id): """Builds a schema from Application builds for a given identifier :param domain: The domain that the export belongs to :param app_id: The app_id that the export belongs to :param unique_form_id: The unique identifier of the item being exported :returns: Returns a ExportDataSchema instance """ app_build_ids = get_built_app_ids_for_app_id(domain, app_id) all_xform_conf = ExportDataSchema() for app_doc in iter_docs(Application.get_db(), app_build_ids): app = Application.wrap(app_doc) xform = app.get_form(unique_form_id).wrapped_xform() xform_conf = FormExportDataSchema._generate_schema_from_xform(xform, app.langs, app.version) all_xform_conf = FormExportDataSchema._merge_schemas(all_xform_conf, xform_conf) return all_xform_conf
def update_schema(self): all_app_ids = get_built_app_ids_for_app_id(self.domain, self.app_id, self.last_processed_version) all_seen_apps = self.apps_with_errors | self.processed_apps to_process = [ app_id for app_id in all_app_ids if app_id not in all_seen_apps ] if self.app_id not in all_seen_apps: to_process.append(self.app_id) for app_doc in iter_docs(Application.get_db(), to_process): if app_doc['doc_type'] == 'RemoteApp': continue app = Application.wrap(app_doc) try: self.update_for_app(app) except AppManagerException: self.apps_with_errors.add(app.get_id) self.last_processed_version = app.version if to_process: self.save()
def update_schema(self): all_app_ids = get_built_app_ids_for_app_id( self.domain, self.app_id, self.last_processed_version ) all_seen_apps = self.apps_with_errors | self.processed_apps to_process = [app_id for app_id in all_app_ids if app_id not in all_seen_apps] if self.app_id not in all_seen_apps: to_process.append(self.app_id) for app_doc in iter_docs(Application.get_db(), to_process): if app_doc['doc_type'] == 'RemoteApp': continue app = Application.wrap(app_doc) try: self.update_for_app(app) except AppManagerException: self.apps_with_errors.add(app.get_id) self.last_processed_version = app.version if to_process: self.save()
def paginate_releases(request, domain, app_id): limit = request.GET.get('limit') only_show_released = json.loads( request.GET.get('only_show_released', 'false')) query = request.GET.get('query') page = int(request.GET.get('page', 1)) page = max(page, 1) try: limit = int(limit) except (TypeError, ValueError): limit = 10 skip = (page - 1) * limit timezone = get_timezone_for_user(request.couch_user, domain) def _get_batch(start_build=None, skip=None): start_build = {} if start_build is None else start_build return Application.get_db().view( 'app_manager/saved_app', startkey=[domain, app_id, start_build], endkey=[domain, app_id], descending=True, limit=limit, skip=skip, wrapper=lambda x: (SavedAppBuild.wrap(x['value'], scrap_old_conventions=False). releases_list_json(timezone)), ).all() if not bool(only_show_released or query): # If user is limiting builds by released status or build comment, it's much # harder to be performant with couch. So if they're not doing so, take shortcuts. total_apps = len(get_built_app_ids_for_app_id(domain, app_id)) saved_apps = _get_batch(skip=skip) else: app_es = (AppES().start((page - 1) * limit).size(limit).sort( 'version', desc=True).domain(domain).is_build().app_id(app_id)) if only_show_released: app_es = app_es.is_released() if query: app_es = app_es.add_query(build_comment(query), queries.SHOULD) try: app_es = app_es.add_query(version(int(query)), queries.SHOULD) except ValueError: pass results = app_es.exclude_source().run() total_apps = results.total app_ids = results.doc_ids apps = get_docs(Application.get_db(), app_ids) saved_apps = [ SavedAppBuild.wrap( app, scrap_old_conventions=False).releases_list_json(timezone) for app in apps ] if toggles.APPLICATION_ERROR_REPORT.enabled(request.couch_user.username): versions = [app['version'] for app in saved_apps] num_errors_dict = _get_error_counts(domain, app_id, versions) for app in saved_apps: app['num_errors'] = num_errors_dict.get(app['version'], 0) num_pages = int(ceil(total_apps / limit)) return json_response({ 'apps': saved_apps, 'pagination': { 'total': total_apps, 'num_pages': num_pages, 'current_page': page, 'more': page * limit < total_apps, # needed when select2 uses this endpoint } })
def paginate_releases(request, domain, app_id): limit = request.GET.get('limit') only_show_released = json.loads(request.GET.get('only_show_released', 'false')) build_comment = request.GET.get('build_comment') page = int(request.GET.get('page', 1)) page = max(page, 1) try: limit = int(limit) except (TypeError, ValueError): limit = 10 skip = (page - 1) * limit timezone = get_timezone_for_user(request.couch_user, domain) def _get_batch(start_build=None, skip=None): start_build = {} if start_build is None else start_build return Application.get_db().view('app_manager/saved_app', startkey=[domain, app_id, start_build], endkey=[domain, app_id], descending=True, limit=limit, skip=skip, wrapper=lambda x: SavedAppBuild.wrap(x['value'], scrap_old_conventions=False).releases_list_json(timezone), ).all() if not bool(only_show_released or build_comment): # If user is limiting builds by released status or build comment, it's much # harder to be performant with couch. So if they're not doing so, take shortcuts. total_apps = len(get_built_app_ids_for_app_id(domain, app_id)) saved_apps = _get_batch(skip=skip) else: app_es = ( AppES() .start((page - 1) * limit) .size(limit) .sort('version', desc=True) .domain(domain) .is_build() .app_id(app_id) ) if only_show_released: app_es = app_es.is_released() if build_comment: app_es = app_es.build_comment(build_comment) results = app_es.exclude_source().run() app_ids = results.doc_ids apps = get_docs(Application.get_db(), app_ids) saved_apps = [ SavedAppBuild.wrap(app, scrap_old_conventions=False).releases_list_json(timezone) for app in apps ] total_apps = results.total j2me_enabled_configs = CommCareBuildConfig.j2me_enabled_config_labels() for app in saved_apps: app['include_media'] = app['doc_type'] != 'RemoteApp' app['j2me_enabled'] = app['menu_item_label'] in j2me_enabled_configs app['target_commcare_flavor'] = ( SavedAppBuild.get(app['_id']).target_commcare_flavor if toggles.TARGET_COMMCARE_FLAVOR.enabled(domain) else 'none' ) if toggles.APPLICATION_ERROR_REPORT.enabled(request.couch_user.username): versions = [app['version'] for app in saved_apps] num_errors_dict = _get_error_counts(domain, app_id, versions) for app in saved_apps: app['num_errors'] = num_errors_dict.get(app['version'], 0) num_pages = int(ceil(total_apps / limit)) return json_response({ 'apps': saved_apps, 'pagination': { 'total': total_apps, 'num_pages': num_pages, 'current_page': page, } })
def paginate_releases(request, domain, app_id): limit = request.GET.get('limit') only_show_released = json.loads(request.GET.get('only_show_released', 'false')) query = request.GET.get('query') page = int(request.GET.get('page', 1)) page = max(page, 1) try: limit = int(limit) except (TypeError, ValueError): limit = 10 skip = (page - 1) * limit timezone = get_timezone_for_user(request.couch_user, domain) def _get_batch(start_build=None, skip=None): start_build = {} if start_build is None else start_build return Application.get_db().view('app_manager/saved_app', startkey=[domain, app_id, start_build], endkey=[domain, app_id], descending=True, limit=limit, skip=skip, wrapper=lambda x: ( SavedAppBuild.wrap(x['value'], scrap_old_conventions=False) .releases_list_json(timezone) ), ).all() if not bool(only_show_released or query): # If user is limiting builds by released status or build comment, it's much # harder to be performant with couch. So if they're not doing so, take shortcuts. total_apps = len(get_built_app_ids_for_app_id(domain, app_id)) saved_apps = _get_batch(skip=skip) else: app_es = ( AppES() .start((page - 1) * limit) .size(limit) .sort('version', desc=True) .domain(domain) .is_build() .app_id(app_id) ) if only_show_released: app_es = app_es.is_released() if query: app_es = app_es.add_query(build_comment(query), queries.SHOULD) try: app_es = app_es.add_query(version(int(query)), queries.SHOULD) except ValueError: pass results = app_es.exclude_source().run() total_apps = results.total app_ids = results.doc_ids apps = get_docs(Application.get_db(), app_ids) saved_apps = [ SavedAppBuild.wrap(app, scrap_old_conventions=False).releases_list_json(timezone) for app in apps ] if toggles.APPLICATION_ERROR_REPORT.enabled(request.couch_user.username): versions = [app['version'] for app in saved_apps] num_errors_dict = _get_error_counts(domain, app_id, versions) for app in saved_apps: app['num_errors'] = num_errors_dict.get(app['version'], 0) num_pages = int(ceil(total_apps / limit)) return json_response({ 'apps': saved_apps, 'pagination': { 'total': total_apps, 'num_pages': num_pages, 'current_page': page, 'more': page * limit < total_apps, # needed when select2 uses this endpoint } })