def _get_user_image(user): image_url = user.extras.get('image_url', None) if not image_url: return helpers.url_for_static('images/user_placeholder_box.png') elif not image_url.startswith('http'): return helpers.url_for_static('uploads/user/%s' % image_url, qualified=True) return image_url
def _create_datastorer_task(self, resource): user = get_action('get_site_user')({'model': model, 'ignore_auth': True, 'defer_commit': True}, {}) context = json.dumps({ 'site_url': h.url_for_static('/', qualified=True), 'apikey': user.get('apikey'), 'site_user_apikey': user.get('apikey'), 'username': user.get('name'), }) data = json.dumps(resource_dictize(resource, {'model': model})) task_id = make_uuid() datastorer_task_status = { 'entity_id': resource.id, 'entity_type': u'resource', 'task_type': u'datastorer', 'key': u'celery_task_id', 'value': task_id, 'last_updated': datetime.now().isoformat() } archiver_task_context = { 'model': model, 'user': user.get('name'), } get_action('task_status_update')(archiver_task_context, datastorer_task_status) celery.send_task("datastorer.upload", args=[context, data], task_id=task_id)
def configure(self, config): """Load config settings for this extension from config file. See IConfigurable. """ if "googleanalytics.id" not in config: msg = "Missing googleanalytics.id in config" raise GoogleAnalyticsException(msg) self.googleanalytics_id = config["googleanalytics.id"] self.googleanalytics_domain = config.get("googleanalytics.domain", "auto") self.googleanalytics_javascript_url = h.url_for_static("/scripts/ckanext-googleanalytics.js") # If resource_prefix is not in config file then write the default value # to the config dict, otherwise templates seem to get 'true' when they # try to read resource_prefix from config. if "googleanalytics_resource_prefix" not in config: config["googleanalytics_resource_prefix"] = commands.DEFAULT_RESOURCE_URL_TAG self.googleanalytics_resource_prefix = config["googleanalytics_resource_prefix"] self.show_downloads = converters.asbool(config.get("googleanalytics.show_downloads", True)) self.track_events = converters.asbool(config.get("googleanalytics.track_events", False)) if not converters.asbool(config.get("ckan.legacy_templates", "false")): p.toolkit.add_resource("fanstatic_library", "ckanext-googleanalytics") # spawn a pool of 5 threads, and pass them queue instance for i in range(5): t = AnalyticsPostThread(self.analytics_queue) t.setDaemon(True) t.start()
def configure(self, config): '''Load config settings for this extension from config file. See IConfigurable. ''' if 'googleanalytics.id' not in config: msg = "Missing googleanalytics.id in config" raise GoogleAnalyticsException(msg) self.googleanalytics_id = config['googleanalytics.id'] self.googleanalytics_domain = config.get( 'googleanalytics.domain', 'auto') self.googleanalytics_javascript_url = h.url_for_static( '/scripts/ckanext-googleanalytics.js') # If resource_prefix is not in config file then write the default value # to the config dict, otherwise templates seem to get 'true' when they # try to read resource_prefix from config. if 'googleanalytics_resource_prefix' not in config: config['googleanalytics_resource_prefix'] = ( commands.DEFAULT_RESOURCE_URL_TAG) self.googleanalytics_resource_prefix = config[ 'googleanalytics_resource_prefix'] self.show_downloads = converters.asbool( config.get('googleanalytics.show_downloads', True)) self.track_events = converters.asbool( config.get('googleanalytics.track_events', False)) if not converters.asbool(config.get('ckan.legacy_templates', 'false')): p.toolkit.add_resource('fanstatic_library', 'ckanext-googleanalytics')
def _add_to_pkg_dict(self, context, pkg_dict): ''' Add key/values to pkg_dict and return it. ''' if pkg_dict['type'] != 'showcase': return pkg_dict # Add a display url for the Showcase image to the pkg dict so template # has access to it. image_url = pkg_dict.get('image_url') pkg_dict[u'image_display_url'] = image_url if image_url and not image_url.startswith('http'): pkg_dict[u'image_url'] = image_url pkg_dict[u'image_display_url'] = \ h.url_for_static('uploads/{0}/{1}' .format(DATASET_TYPE_NAME, pkg_dict.get('image_url')), qualified=True) # Add dataset count pkg_dict[u'num_datasets'] = len(toolkit.get_action('ckanext_showcase_package_list') (context, {'showcase_id': pkg_dict['id']})) # Rendered notes pkg_dict[u'showcase_notes_formatted'] = h.render_markdown(pkg_dict['notes']) return pkg_dict
def h_organization_image(self, org, show_placeholder_by_default = True): if org.get('image_display_url', None): return org.get('image_display_url') if paste.deploy.converters.asbool(config.get('dp.show_organization_placeholder_image', show_placeholder_by_default)): return h.url_for_static('/base/images/placeholder-organization.png') return None
def group_list_dictize(obj_list, context, sort_key=lambda x:x['display_name'], reverse=False, with_package_counts=True): active = context.get('active', True) with_private = context.get('include_private_packages', False) if with_package_counts: query = search.PackageSearchQuery() q = {'q': '+capacity:public' if not with_private else '*:*', 'fl': 'groups', 'facet.field': ['groups', 'owner_org'], 'facet.limit': -1, 'rows': 1} query.run(q) result_list = [] for obj in obj_list: if context.get('with_capacity'): obj, capacity = obj group_dict = d.table_dictize(obj, context, capacity=capacity) else: group_dict = d.table_dictize(obj, context) group_dict.pop('created') if active and obj.state not in ('active', 'pending'): continue group_dict['display_name'] = (group_dict.get('title') or group_dict.get('name')) image_url = group_dict.get('image_url') group_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): #munge here should not have an effect only doing it incase #of potential vulnerability of dodgy api input image_url = munge.munge_filename(image_url) group_dict['image_display_url'] = h.url_for_static( 'uploads/group/%s' % group_dict.get('image_url'), qualified=True ) if with_package_counts: facets = query.facets if obj.is_organization: group_dict['packages'] = facets['owner_org'].get(obj.id, 0) else: group_dict['packages'] = facets['groups'].get(obj.name, 0) if context.get('for_view'): if group_dict['is_organization']: plugin = plugins.IOrganizationController else: plugin = plugins.IGroupController for item in plugins.PluginImplementations(plugin): group_dict = item.before_view(group_dict) result_list.append(group_dict) return sorted(result_list, key=sort_key, reverse=reverse)
def _get_site_url(): """ Returns the url of the ckan website :return: the url of the ckan website """ try: return h.url_for_static('/', qualified=True) except AttributeError: return config.get('ckan.site_url', '')
def group_dictize(group, context): model = context['model'] result_dict = d.table_dictize(group, context) result_dict['display_name'] = group.display_name result_dict['extras'] = extras_dict_dictize( group._extras, context) context['with_capacity'] = True result_dict['packages'] = d.obj_list_dictize( _get_members(context, group, 'packages'), context) query = search.PackageSearchQuery() if group.is_organization: q = {'q': 'owner_org:"%s" +capacity:public' % group.id, 'rows': 1} else: q = {'q': 'groups:"%s" +capacity:public' % group.name, 'rows': 1} result_dict['package_count'] = query.run(q)['count'] result_dict['tags'] = tag_list_dictize( _get_members(context, group, 'tags'), context) result_dict['groups'] = group_list_dictize( _get_members(context, group, 'groups'), context) result_dict['users'] = user_list_dictize( _get_members(context, group, 'users'), context) context['with_capacity'] = False if context.get('for_view'): if result_dict['is_organization']: plugin = plugins.IOrganizationController else: plugin = plugins.IGroupController for item in plugins.PluginImplementations(plugin): result_dict = item.before_view(result_dict) image_url = result_dict.get('image_url') result_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): #munge here should not have an effect only doing it incase #of potential vulnerability of dodgy api input image_url = munge.munge_filename(image_url) result_dict['image_display_url'] = h.url_for_static( 'uploads/group/%s' % result_dict.get('image_url'), qualified = True ) return result_dict
def configure(self, config): '''Load config settings for this extension from config file. See IConfigurable. ''' if 'googleanalytics.id' not in config: msg = "Missing googleanalytics.id in config" raise GoogleAnalyticsException(msg) self.googleanalytics_id = config['googleanalytics.id'] self.googleanalytics_domain = config.get( 'googleanalytics.domain', 'auto') self.googleanalytics_fields = ast.literal_eval(config.get( 'googleanalytics.fields', '{}')) googleanalytics_linked_domains = config.get( 'googleanalytics.linked_domains', '' ) self.googleanalytics_linked_domains = [ x.strip() for x in googleanalytics_linked_domains.split(',') if x ] if self.googleanalytics_linked_domains: self.googleanalytics_fields['allowLinker'] = 'true' self.googleanalytics_javascript_url = h.url_for_static( '/scripts/ckanext-googleanalytics.js') # If resource_prefix is not in config file then write the default value # to the config dict, otherwise templates seem to get 'true' when they # try to read resource_prefix from config. if 'googleanalytics_resource_prefix' not in config: config['googleanalytics_resource_prefix'] = ( commands.DEFAULT_RESOURCE_URL_TAG) self.googleanalytics_resource_prefix = config[ 'googleanalytics_resource_prefix'] self.show_downloads = converters.asbool( config.get('googleanalytics.show_downloads', True)) self.track_events = converters.asbool( config.get('googleanalytics.track_events', False)) self.enable_user_id = converters.asbool( config.get('googleanalytics.enable_user_id', False)) if not converters.asbool(config.get('ckan.legacy_templates', 'false')): p.toolkit.add_resource('fanstatic_library', 'ckanext-googleanalytics') # spawn a pool of 5 threads, and pass them queue instance for i in range(5): t = AnalyticsPostThread(self.analytics_queue) t.setDaemon(True) t.start()
def configure(self, config): '''Load config settings for this extension from config file. See IConfigurable. ''' self.googleanalytics_ids = [] if 'googleanalytics.ids' not in config: msg = "Missing googleanalytics.ids in config" log.warn(msg) return # raise GoogleAnalyticsBasicException(msg) self.googleanalytics_ids = config['googleanalytics.ids'].split() self.googleanalytics_javascript_url = h.url_for_static( '/scripts/ckanext-googleanalytics.js')
def pages_upload(context, data_dict): try: p.toolkit.check_access('ckanext_pages_upload', context, data_dict) except p.toolkit.NotAuthorized: p.toolkit.abort(401, p.toolkit._('Not authorized to see this page')) upload = uploader.Upload('page_images') upload.update_data_dict(data_dict, 'image_url', 'upload', 'clear_upload') upload.upload() image_url = data_dict.get('image_url') if image_url: image_url = h.url_for_static( 'uploads/page_images/%s' % image_url, qualified = True ) return {'url': image_url}
def configure(self, config): '''Load config settings for this extension from config file. See IConfigurable. ''' if 'googleanalytics.id' not in config: msg = "Missing googleanalytics.id in config" raise GoogleAnalyticsException(msg) self.googleanalytics_id = config['googleanalytics.id'] self.googleanalytics_domain = config.get( 'googleanalytics.domain', 'auto') self.googleanalytics_javascript_url = h.url_for_static( '/scripts/ckanext-googleanalytics.js') self.googleanalytics_type = config.get('googleanalytics.type', 'classic') if self.googleanalytics_type == 'universal': self.analytics_html = 'googleanalytics/snippets/googleanalytics_header_ua.html' self.analytics_js = 'ckanext-googleanalytics/googleanalytics_event_tracking_ua.js' elif self.googleanalytics_type == 'classic': self.analytics_html = 'googleanalytics/snippets/googleanalytics_header.html' self.analytics_js = 'ckanext-googleanalytics/googleanalytics_event_tracking.js' else: raise GoogleAnalyticsException("Invalid 'googleanalytics.type' value '%s'. Should be " "'classic' or 'universal'." % self.googleanalytics_type) # If resource_prefix is not in config file then write the default value # to the config dict, otherwise templates seem to get 'true' when they # try to read resource_prefix from config. if 'googleanalytics_resource_prefix' not in config: config['googleanalytics_resource_prefix'] = ( commands.DEFAULT_RESOURCE_URL_TAG) self.googleanalytics_resource_prefix = config[ 'googleanalytics_resource_prefix'] self.show_downloads = converters.asbool( config.get('googleanalytics.show_downloads', True)) self.track_events = converters.asbool( config.get('googleanalytics.track_events', False)) if not converters.asbool(config.get('ckan.legacy_templates', 'false')): p.toolkit.add_resource('fanstatic_library', 'ckanext-googleanalytics')
def _add_user_extras(user_obj, user_dict): for key, value in user_obj.extras.iteritems(): if key in user_dict: log.warning("Trying to override user data with extra variable '%s'", key) continue if key in ('blog', 'www_page', 'translations'): if value: user_dict[key] = json.loads(value) else: user_dict[key] = value image_url = user_dict.get('image_url', None) user_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): image_url = munge.munge_filename(image_url) user_dict['image_display_url'] = helpers.url_for_static( 'uploads/user/%s' % user_dict.get('image_url'), qualified=True ) return user_dict
def view_widget(self, id): ''' Embeded page for widget visualization. ''' # We need to investigate more about context context = { #'model': model, 'session': model.Session, #'user': c.user or c.author, 'auth_user_obj': c.userobj } try: c.package = get_action('package_show')(context, {'id': id}) data_dict = {'resource': c.resource, 'package': c.package, 'parameters': request.params } log.warning(str(c.package['organization']['image_url'])) ## Fix for unformatted images in organization dictionary CKAN ## https://github.com/ckan/ckan/issues/1934 if c.package['organization']['image_url'] and not c.package['organization']['image_url'].startswith('http'): image_url = c.package['organization']['image_url'] c.package['organization']['image_url'] = h.url_for_static( 'uploads/group/%s' % image_url, qualified = True ) ##END Fix for unformatted images in organization dictionary CKAN if 'widget_type' in request.params: if request.params['widget_type'] == 'wide' : return p.toolkit.render('wide_widget.html', data_dict) else: return p.toolkit.render('widget.html', data_dict) else: return p.toolkit.render('widget.html', data_dict) except NotFound: abort(404, _('Resource not found')) except NotAuthorized: abort(401, _('Unauthorized to read resource %s') % id) except: abort(500, _('There was an internal error %s') % id)
def test_url_for_static_with_root_path(self): url = '/my/custom/path/foo/my-asset/file.txt' generated_url = h.url_for_static('/my-asset/file.txt') eq_(generated_url, url)
def package_update(context, data_dict): '''Update a dataset (package). You must be authorized to edit the dataset and the groups that it belongs to. Plugins may change the parameters of this function depending on the value of the dataset's ``type`` attribute, see the ``IDatasetForm`` plugin interface. For further parameters see ``package_create()``. :param id: the name or id of the dataset to update :type id: string :returns: the updated dataset (if 'return_package_dict' is True in the context, which is the default. Otherwise returns just the dataset id) :rtype: dictionary ''' model = context['model'] user = context['user'] name_or_id = data_dict.get("id") or data_dict['name'] pkg = model.Package.get(name_or_id) if pkg is None: raise NotFound(_('Package was not found.')) context["package"] = pkg data_dict["id"] = pkg.id # FIXME: first modifications to package_updade begin here: # tag strings are reconstructed because validators are stripping # tags passed and only taking taks as tag_string values # image upload support has also been added here old_data = get_action('package_show')(context, {'id': pkg.id}) ''' Constructing the tag_string from the given tags. There must be at least one tag, otherwise the tag_string will be empty and a validation error will be raised. ''' if not data_dict.get('tag_string'): data_dict['tag_string'] = ', '.join( h.dict_list_reduce(data_dict.get('tags', {}), 'name')) for key, value in old_data.iteritems() : if key not in data_dict : data_dict[key] = value #data_dict['resources'] = data_dict.get('resources', old_data.get('resources')) # iso_topic_cat = data_dict.get('iso_topic_string', []) # if isinstance(iso_topic_cat, basestring): # iso_topic_cat = [iso_topic_cat] # # data_dict['iso_topic_string'] = ','.join(iso_topic_cat) #Set the package last modified date data_dict['record_last_modified'] = str(datetime.date.today()) # If the Created Date has not yet been set, then set it if data_dict['edc_state'] == 'DRAFT' and not data_dict.get('record_create_date'): data_dict['record_create_date'] = str(datetime.date.today()) # If the Publish Date has not yet been set, then set it if data_dict['edc_state'] == 'PUBLISHED' and not data_dict.get('record_publish_date'): data_dict['record_publish_date'] = str(datetime.date.today()) # If the Archive Date has not yet been set, then set it if data_dict['edc_state'] == 'ARCHIVED' and not data_dict.get('record_archive_date'): data_dict['record_archive_date'] = str(datetime.date.today()) _check_access('package_update', context, data_dict) # get the schema package_plugin = lib_plugins.lookup_package_plugin(pkg.type) if 'schema' in context: schema = context['schema'] else: schema = package_plugin.update_package_schema() image_url = old_data.get('image_url', None) upload = uploader.Upload('edc', image_url) upload.update_data_dict(data_dict, 'image_url', 'image_upload', 'clear_upload') #Adding image display url for the uploaded image image_url = data_dict.get('image_url') data_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): image_url = munge.munge_filename(image_url) data_dict['image_display_url'] = h.url_for_static('uploads/edc/%s' % data_dict.get('image_url'), qualified=True) if 'api_version' not in context: # check_data_dict() is deprecated. If the package_plugin has a # check_data_dict() we'll call it, if it doesn't have the method we'll # do nothing. check_data_dict = getattr(package_plugin, 'check_data_dict', None) if check_data_dict: try: package_plugin.check_data_dict(data_dict, schema) except TypeError: # Old plugins do not support passing the schema so we need # to ensure they still work. package_plugin.check_data_dict(data_dict) # FIXME: modifications to package_update end here^ data, errors = _validate(data_dict, schema, context) # log.debug('package_update validate_errs=%r user=%s package=%s data=%r', # errors, context.get('user'), # context.get('package').name if context.get('package') else '', # data) if errors: model.Session.rollback() raise ValidationError(errors) rev = model.repo.new_revision() rev.author = user if 'message' in context: rev.message = context['message'] else: rev.message = _(u'REST API: Update object %s') % data.get("name") #avoid revisioning by updating directly model.Session.query(model.Package).filter_by(id=pkg.id).update( {"metadata_modified": datetime.datetime.utcnow()}) model.Session.refresh(pkg) pkg = model_save.package_dict_save(data, context) context_org_update = context.copy() context_org_update['ignore_auth'] = True context_org_update['defer_commit'] = True _get_action('package_owner_org_update')(context_org_update, {'id': pkg.id, 'organization_id': pkg.owner_org}) for item in plugins.PluginImplementations(plugins.IPackageController): item.edit(pkg) item.after_update(context, data) upload.upload(uploader.get_max_image_size()) #TODO the next two blocks are copied from ckan/ckan/logic/action/update.py # This codebase is currently hard to maintain because large chunks of the # CKAN action API and the CKAN controllers are simply overriden. This is # probably worse than just forking CKAN would have been, because in that # case at least we could track changes. - @deniszgonjanin # Needed to let extensions know the new resources ids model.Session.flush() if data.get('resources'): for index, resource in enumerate(data['resources']): resource['id'] = pkg.resources[index].id # Create default views for resources if necessary if data.get('resources'): logic.get_action('package_create_default_resource_views')( {'model': context['model'], 'user': context['user'], 'ignore_auth': True}, {'package': data}) if not context.get('defer_commit'): model.repo.commit() log.debug('Updated object %s' % pkg.name) return_id_only = context.get('return_id_only', False) # Make sure that a user provided schema is not used on package_show context.pop('schema', None) # we could update the dataset so we should still be able to read it. context['ignore_auth'] = True output = data_dict['id'] if return_id_only \ else _get_action('package_show')(context, {'id': data_dict['id']}) ''' Send state change notifications if required; Added by Khalegh Mamakani Using a thread to run the job in the background so that package_update will not wait for notifications sending. ''' old_state = old_data.get('edc_state') context = {'model': model, 'session': model.Session, 'user': c.user or c.author, 'auth_user_obj': c.userobj} dataset_url = config.get('ckan.site_url') + h.url_for(controller='package', action="read", id = data_dict['name']) import threading notify_thread = threading.Thread(target=check_record_state, args=(context, old_state, data_dict, g.site_title, g.site_url, dataset_url) ) notify_thread.start() return output
def test_url_for_static_adds_starting_slash_if_url_doesnt_have_it(self): slashless_url = 'ckan.jpg' url = '/' + slashless_url eq_(h.url_for_static(slashless_url), url)
def generate_url(package): site_url = toolkit.config.get('ckan.site_url') relative_path = h.url_for_static( controller='package', action='read', id=package['name']) return ''.join([site_url, relative_path])
def localized_url_for_static(link): return h.url_for_static("{lang}/{link}".format(lang=h.lang(), link=link))
def group_dictize(group, context): result_dict = d.table_dictize(group, context) result_dict['display_name'] = group.display_name result_dict['extras'] = extras_dict_dictize( group._extras, context) include_datasets = context.get('include_datasets', True) q = { 'facet': 'false', 'rows': 0, } if group.is_organization: q['fq'] = 'owner_org:"{0}"'.format(group.id) else: q['fq'] = 'groups:"{0}"'.format(group.name) is_group_member = (context.get('user') and new_authz.has_user_permission_for_group_or_org(group.id, context.get('user'), 'read')) if is_group_member: context['ignore_capacity_check'] = True if include_datasets: q['rows'] = 1000 # Only the first 1000 datasets are returned search_results = logic.get_action('package_search')(context, q) if include_datasets: result_dict['packages'] = search_results['results'] result_dict['package_count'] = search_results['count'] context['with_capacity'] = True result_dict['tags'] = tag_list_dictize( _get_members(context, group, 'tags'), context) result_dict['groups'] = group_list_dictize( _get_members(context, group, 'groups'), context) result_dict['users'] = user_list_dictize( _get_members(context, group, 'users'), context) context['with_capacity'] = False if context.get('for_view'): if result_dict['is_organization']: plugin = plugins.IOrganizationController else: plugin = plugins.IGroupController for item in plugins.PluginImplementations(plugin): result_dict = item.before_view(result_dict) image_url = result_dict.get('image_url') result_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): #munge here should not have an effect only doing it incase #of potential vulnerability of dodgy api input image_url = munge.munge_filename(image_url) result_dict['image_display_url'] = h.url_for_static( 'uploads/group/%s' % result_dict.get('image_url'), qualified = True ) return result_dict
def group_dictize(group, context, include_groups=True, include_tags=True, include_users=True, include_extras=True, packages_field='datasets', **kw): ''' Turns a Group object and related into a dictionary. The related objects like tags are included unless you specify it in the params. :param packages_field: determines the format of the `packages` field - can be `datasets` or None. ''' assert packages_field in ('datasets', 'dataset_count', None) if packages_field == 'dataset_count': dataset_counts = context.get('dataset_counts', None) result_dict = d.table_dictize(group, context) result_dict.update(kw) result_dict['display_name'] = group.title or group.name if include_extras: result_dict['extras'] = extras_dict_dictize( group._extras, context) context['with_capacity'] = True if packages_field: def get_packages_for_this_group(group_, just_the_count=False): # Ask SOLR for the list of packages for this org/group q = { 'facet': 'false', 'rows': 0, } if group_.is_organization: q['fq'] = 'owner_org:"{0}"'.format(group_.id) else: q['fq'] = 'groups:"{0}"'.format(group_.name) # Allow members of organizations to see private datasets. if group_.is_organization: is_group_member = (context.get('user') and authz.has_user_permission_for_group_or_org( group_.id, context.get('user'), 'read')) if is_group_member: context['ignore_capacity_check'] = True if not just_the_count: # Is there a packages limit in the context? try: packages_limit = context['limits']['packages'] except KeyError: q['rows'] = 1000 # Only the first 1000 datasets are returned else: q['rows'] = packages_limit search_context = dict((k, v) for (k, v) in context.items() if k != 'schema') search_results = logic.get_action('package_search')(search_context, q) return search_results['count'], search_results['results'] if packages_field == 'datasets': package_count, packages = get_packages_for_this_group(group) result_dict['packages'] = packages else: if dataset_counts is None: package_count, packages = get_packages_for_this_group( group, just_the_count=True) else: # Use the pre-calculated package_counts passed in. facets = dataset_counts if group.is_organization: package_count = facets['owner_org'].get(group.id, 0) else: package_count = facets['groups'].get(group.name, 0) result_dict['package_count'] = package_count if include_tags: # group tags are not creatable via the API yet, but that was(/is) a # future intention (see kindly's commit 5c8df894 on 2011/12/23) result_dict['tags'] = tag_list_dictize( _get_members(context, group, 'tags'), context) if include_groups: # these sub-groups won't have tags or extras for speed result_dict['groups'] = group_list_dictize( _get_members(context, group, 'groups'), context, include_groups=True) if include_users: result_dict['users'] = user_list_dictize( _get_members(context, group, 'users'), context) context['with_capacity'] = False if context.get('for_view'): if result_dict['is_organization']: plugin = plugins.IOrganizationController else: plugin = plugins.IGroupController for item in plugins.PluginImplementations(plugin): result_dict = item.before_view(result_dict) image_url = result_dict.get('image_url') result_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): #munge here should not have an effect only doing it incase #of potential vulnerability of dodgy api input image_url = munge.munge_filename_legacy(image_url) result_dict['image_display_url'] = h.url_for_static( 'uploads/group/%s' % result_dict.get('image_url'), qualified=True ) return result_dict
def test_url_for_static_qualified_with_root_path(self): url = "http://example.com/my/custom/path/foo/my-asset/file.txt" generated_url = h.url_for_static("/my-asset/file.txt", qualified=True) assert generated_url == url
def test_url_for_static_with_root_path_and_script_name_env( self, monkeypatch): monkeypatch.setitem(os.environ, "SCRIPT_NAME", "/my/custom/path") url = "http://example.com/my/custom/path/foo/my-asset/file.txt" generated_url = h.url_for_static("/my-asset/file.txt", qualified=True) assert generated_url == url
def test_url_for_static_with_root_path(self): url = "/my/custom/path/foo/my-asset/file.txt" generated_url = h.url_for_static("/my-asset/file.txt") assert generated_url == url
def test_url_for_static_raises_when_called_with_protocol_relative(self): url = "//assets.ckan.org/ckan.jpg" with pytest.raises(CkanUrlException): h.url_for_static(url)
def test_url_for_static_raises_when_called_with_external_urls(self): url = "http://assets.ckan.org/ckan.jpg" with pytest.raises(CkanUrlException): h.url_for_static(url)
def user_dictize(user: Union[model.User, tuple[model.User, str]], context: Context, include_password_hash: bool = False, include_plugin_extras: bool = False) -> dict[str, Any]: model = context['model'] if context.get('with_capacity'): # Fix type: "User" is not iterable user, capacity = user #type: ignore result_dict = d.table_dictize(user, context, capacity=capacity) else: result_dict = d.table_dictize(user, context) assert isinstance(user, model.User) password_hash = result_dict.pop('password') del result_dict['reset_key'] result_dict['display_name'] = user.display_name result_dict['email_hash'] = user.email_hash result_dict['number_created_packages'] = user.number_created_packages( include_private_and_draft=context.get( 'count_private_and_draft_datasets', False)) requester = context.get('user') result_dict.pop('reset_key', None) apikey = result_dict.pop('apikey', None) email = result_dict.pop('email', None) plugin_extras = result_dict.pop('plugin_extras', None) if context.get('keep_email', False): result_dict['email'] = email if context.get('keep_apikey', False): result_dict['apikey'] = apikey if requester == user.name: result_dict['apikey'] = apikey result_dict['email'] = email if authz.is_sysadmin(requester): result_dict['apikey'] = apikey result_dict['email'] = email if include_password_hash: result_dict['password_hash'] = password_hash if include_plugin_extras: result_dict['plugin_extras'] = copy.deepcopy( plugin_extras) if plugin_extras else plugin_extras image_url = result_dict.get('image_url') result_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): # munge here should not have any effect, only doing it in case # of potential vulnerability of dodgy api input. image_url = munge.munge_filename_legacy(image_url) result_dict['image_display_url'] = h.url_for_static( 'uploads/user/%s' % result_dict.get('image_url'), qualified=True) return result_dict
def config_option_update(context, data_dict): ''' .. versionadded:: 2.4 Allows to modify some CKAN runtime-editable config options It takes arbitrary key, value pairs and checks the keys against the config options update schema. If some of the provided keys are not present in the schema a :py:class:`~ckan.plugins.logic.ValidationError` is raised. The values are then validated against the schema, and if validation is passed, for each key, value config option: * It is stored on the ``system_info`` database table * The Pylons ``config`` object is updated. * The ``app_globals`` (``g``) object is updated (this only happens for options explicitly defined in the ``app_globals`` module. The following lists a ``key`` parameter, but this should be replaced by whichever config options want to be updated, eg:: get_action('config_option_update)({}, { 'ckan.site_title': 'My Open Data site', 'ckan.homepage_layout': 2, }) :param key: a configuration option key (eg ``ckan.site_title``). It must be present on the ``update_configuration_schema`` :type key: string :returns: a dictionary with the options set :rtype: dictionary .. note:: You can see all available runtime-editable configuration options calling the :py:func:`~ckan.logic.action.get.config_option_list` action .. note:: Extensions can modify which configuration options are runtime-editable. For details, check :doc:`/extensions/remote-config-update`. .. warning:: You should only add config options that you are comfortable they can be edited during runtime, such as ones you've added in your own extension, or have reviewed the use of in core CKAN. ''' model = context['model'] _check_access('config_option_update', context, data_dict) schema = schema_.update_configuration_schema() available_options = schema.keys() provided_options = data_dict.keys() unsupported_options = set(provided_options) - set(available_options) if unsupported_options: msg = 'Configuration option(s) \'{0}\' can not be updated'.format( ' '.join(list(unsupported_options))) raise ValidationError(msg, error_summary={'message': msg}) upload = uploader.get_uploader('admin') upload.update_data_dict(data_dict, 'ckan.site_logo', 'logo_upload', 'clear_logo_upload') upload.upload(uploader.get_max_image_size()) data, errors = _validate(data_dict, schema, context) if errors: model.Session.rollback() raise ValidationError(errors) for key, value in six.iteritems(data): # Set full Logo url if key == 'ckan.site_logo' and value and not value.startswith('http')\ and not value.startswith('/'): image_path = 'uploads/admin/' value = h.url_for_static('{0}{1}'.format(image_path, value)) # Save value in database model.set_system_info(key, value) # Update CKAN's `config` object config[key] = value # Only add it to the app_globals (`g`) object if explicitly defined # there globals_keys = app_globals.app_globals_from_config_details.keys() if key in globals_keys: app_globals.set_app_global(key, value) # Update the config update timestamp model.set_system_info('ckan.config_update', str(time.time())) log.info('Updated config options: {0}'.format(data)) return data
def _get_site_url(): try: return h.url_for_static('/', qualified=True) except AttributeError: return config.get('ckan.site_url', '')
def _call(cls, args, kwargs): assert len(args) == 1 return h.url_for_static(args[0], **kwargs)
def test_url_for_static_adds_starting_slash_if_url_doesnt_have_it(self): slashless_url = "ckan.jpg" url = "/" + slashless_url assert h.url_for_static(slashless_url) == url
def group_dictize(group, context, include_groups=True, include_tags=True, include_users=True, include_extras=True, packages_field='datasets', **kw): ''' Turns a Group object and related into a dictionary. The related objects like tags are included unless you specify it in the params. :param packages_field: determines the format of the `packages` field - can be `datasets`, `dataset_count` or None. ''' assert packages_field in ('datasets', 'dataset_count', None) if packages_field == 'dataset_count': dataset_counts = context.get('dataset_counts', None) result_dict = d.table_dictize(group, context) result_dict.update(kw) result_dict['display_name'] = group.title or group.name if include_extras: result_dict['extras'] = extras_dict_dictize(group._extras, context) context['with_capacity'] = True if packages_field: def get_packages_for_this_group(group_, just_the_count=False): # Ask SOLR for the list of packages for this org/group q = { 'facet': 'false', 'rows': 0, } if group_.is_organization: q['fq'] = 'owner_org:"{0}"'.format(group_.id) else: q['fq'] = 'groups:"{0}"'.format(group_.name) # Allow members of organizations to see private datasets. if group_.is_organization: is_group_member = (context.get('user') and authz.has_user_permission_for_group_or_org( group_.id, context.get('user'), 'read')) if is_group_member: q['include_private'] = True if not just_the_count: # package_search limits 'rows' anyway, so this is only if you # want even fewer try: packages_limit = context['limits']['packages'] except KeyError: del q['rows'] # leave it to package_search to limit it else: q['rows'] = packages_limit search_context = dict( (k, v) for (k, v) in context.items() if k != 'schema') search_results = logic.get_action('package_search')(search_context, q) return search_results['count'], search_results['results'] if packages_field == 'datasets': package_count, packages = get_packages_for_this_group(group) result_dict['packages'] = packages else: if dataset_counts is None: package_count, packages = get_packages_for_this_group( group, just_the_count=True) else: # Use the pre-calculated package_counts passed in. facets = dataset_counts if group.is_organization: package_count = facets['owner_org'].get(group.id, 0) else: package_count = facets['groups'].get(group.name, 0) result_dict['package_count'] = package_count if include_tags: # group tags are not creatable via the API yet, but that was(/is) a # future intention (see kindly's commit 5c8df894 on 2011/12/23) result_dict['tags'] = tag_list_dictize( _get_members(context, group, 'tags'), context) if include_groups: # these sub-groups won't have tags or extras for speed result_dict['groups'] = group_list_dictize(_get_members( context, group, 'groups'), context, include_groups=True) if include_users: result_dict['users'] = user_list_dictize( _get_members(context, group, 'users'), context) context['with_capacity'] = False if context.get('for_view'): if result_dict['is_organization']: plugin = plugins.IOrganizationController else: plugin = plugins.IGroupController for item in plugins.PluginImplementations(plugin): result_dict = item.before_view(result_dict) image_url = result_dict.get('image_url') result_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): #munge here should not have an effect only doing it incase #of potential vulnerability of dodgy api input image_url = munge.munge_filename_legacy(image_url) result_dict['image_display_url'] = h.url_for_static( 'uploads/group/%s' % result_dict.get('image_url'), qualified=True) return result_dict
def _site_logo(self, hostname, default=None): logo = self.logos.get(hostname, self.logos.get('default', None)) if logo: return literal('<img src="%s" class="site-logo" />' % helpers.url_for_static("/images/logo/%s" % logo)) else: return self._short_domain(hostname, default)
def group_list_dictize(obj_list, context, sort_key=lambda x: x['display_name'], reverse=False, with_package_counts=True): active = context.get('active', True) with_private = context.get('include_private_packages', False) if with_package_counts: query = search.PackageSearchQuery() q = { 'q': '+capacity:public' if not with_private else '*:*', 'fl': 'groups', 'facet.field': ['groups', 'owner_org'], 'facet.limit': -1, 'rows': 1 } query.run(q) result_list = [] for obj in obj_list: if context.get('with_capacity'): obj, capacity = obj group_dict = d.table_dictize(obj, context, capacity=capacity) else: group_dict = d.table_dictize(obj, context) group_dict.pop('created') if active and obj.state not in ('active', 'pending'): continue group_dict['display_name'] = (group_dict.get('title') or group_dict.get('name')) image_url = group_dict.get('image_url') group_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): #munge here should not have an effect only doing it incase #of potential vulnerability of dodgy api input image_url = munge.munge_filename(image_url) group_dict['image_display_url'] = h.url_for_static( 'uploads/group/%s' % group_dict.get('image_url'), qualified=True) if with_package_counts: facets = query.facets if obj.is_organization: group_dict['packages'] = facets['owner_org'].get(obj.id, 0) else: group_dict['packages'] = facets['groups'].get(obj.name, 0) if context.get('for_view'): if group_dict['is_organization']: plugin = plugins.IOrganizationController else: plugin = plugins.IGroupController for item in plugins.PluginImplementations(plugin): group_dict = item.before_view(group_dict) result_list.append(group_dict) return sorted(result_list, key=sort_key, reverse=reverse)
def _call(cls, args: Sequence[Any], kwargs: dict[str, Any]): assert len(args) == 1 return h.url_for_static(args[0], **kwargs)
def test_url_for_static(self): url = '/assets/ckan.jpg' eq_(h.url_for_static(url), url)
def test_url_for_static_converts_unicode_strings_to_regular_strings(self): url = u'/ckan.jpg' assert isinstance(h.url_for_static(url), str)
def test_url_for_static_with_root_path_and_script_name_env(self): url = 'http://example.com/my/custom/path/foo/my-asset/file.txt' generated_url = h.url_for_static('/my-asset/file.txt', qualified=True) eq_(generated_url, url)
def get_bureau_info(bureau_code): """ Maps Bureau Codes to a title, logo, and dataset URL. bureau_code: bureau code string or a list of bureau code strings. returns dict(title, url, code, logo) or None if there was an error or the bureau code does not exist in our list. """ if not bureau_code: return None if six.PY3: WEB_PATH = '/images/logos/' else: WEB_PATH = '/fanstatic/datagovtheme/images/logos/' LOCAL_PATH = 'fanstatic_library/images/logos/' # handle both '007:15', or ['007:15', '007:16'] if isinstance(bureau_code, list): bureau_code = bureau_code[0] try: agency_part, bureau_part = bureau_code.split(':') except ValueError: log.warning('bureau code is invalid code=%s' % bureau_code) return None controller = 'dataset' if not p.toolkit.check_ckan_version(min_version='2.9'): # TODO remove this after CKAN 2.8 support is dropped controller = 'package' # TODO in python 3, replace pkg_resources with [importlib-resources](https://pypi.org/project/importlib-resources/) bureau_filename = pkg_resources.resource_filename( 'ckanext.datagovtheme.data', 'omb_bureau_codes.csv') if sys.version_info >= (3, 0): # Python 3 csv.reader wants text data bureau_file = open(bureau_filename, 'r', newline='', encoding='utf8') else: # Python 2 csv.reader wants binary data bureau_file = open(bureau_filename, 'rb') # Should this be cached in memory as an index to speed things up? bureau_table = csv.reader(bureau_file) for row in bureau_table: # We're doing the zfill to pad for 000 every lookup, more reason to # cache this or do a transform when the file is imported into the # repository. if agency_part == row[2].zfill(3) and bureau_part == row[3].zfill(2): bureau_title = row[1] bureau_url = h.url_for(controller=controller, action='search', q='bureauCode:"%s"' % bureau_code) break else: log.warning('omb_bureau_codes.csv is empty') return None # TODO in python 3, use a context manager since we won't need the conditional `open` bureau_file.close() # check logo image file exists or not # should this be cached as in index to speed this up? bureau_logo = None for ext in ['png', 'gif', 'jpg']: logo_filename = '%s-%s.%s' % (agency_part, bureau_part, ext) # We should probably be using pre_resources here, too, but we also need # to add the logos as assets. That seems to be magically working right # now? if os.path.isfile( os.path.join(os.path.dirname(__file__), LOCAL_PATH) + logo_filename): bureau_logo = h.url_for_static(WEB_PATH + logo_filename) break return { 'title': bureau_title, 'code': bureau_code, 'logo': bureau_logo, 'url': bureau_url, }
def package_update(context, data_dict): '''Update a dataset (package). You must be authorized to edit the dataset and the groups that it belongs to. Plugins may change the parameters of this function depending on the value of the dataset's ``type`` attribute, see the ``IDatasetForm`` plugin interface. For further parameters see ``package_create()``. :param id: the name or id of the dataset to update :type id: string :returns: the updated dataset (if 'return_package_dict' is True in the context, which is the default. Otherwise returns just the dataset id) :rtype: dictionary ''' model = context['model'] user = context['user'] name_or_id = data_dict.get("id") or data_dict['name'] pkg = model.Package.get(name_or_id) if pkg is None: raise NotFound(_('Package was not found.')) context["package"] = pkg data_dict["id"] = pkg.id # FIXME: first modifications to package_updade begin here: # tag strings are reconstructed because validators are stripping # tags passed and only taking tags as tag_string values # image upload support has also been added here old_data = get_action('package_show')(context, {'id': pkg.id}) ''' Constructing the tag_string from the given tags. There must be at least one tag, otherwise the tag_string will be empty and a validation error will be raised. ''' if not data_dict.get('tag_string'): data_dict['tag_string'] = ', '.join( h.dict_list_reduce(data_dict.get('tags', {}), 'name')) for key, value in old_data.iteritems(): if key not in data_dict: data_dict[key] = value # data_dict['resources'] = data_dict.get('resources', old_data.get('resources')) # iso_topic_cat = data_dict.get('iso_topic_string', []) # if isinstance(iso_topic_cat, basestring): # iso_topic_cat = [iso_topic_cat] # # data_dict['iso_topic_string'] = ','.join(iso_topic_cat) # Set the package last modified date data_dict['record_last_modified'] = str(datetime.date.today()) # If the Created Date has not yet been set, then set it if data_dict['edc_state'] == 'DRAFT' and not data_dict.get( 'record_create_date'): data_dict['record_create_date'] = str(datetime.date.today()) # If the Publish Date has not yet been set, then set it if data_dict['edc_state'] == 'PUBLISHED' and not data_dict.get( 'record_publish_date'): data_dict['record_publish_date'] = str(datetime.date.today()) # If the Archive Date has not yet been set, then set it if data_dict['edc_state'] == 'ARCHIVED' and not data_dict.get( 'record_archive_date'): data_dict['record_archive_date'] = str(datetime.date.today()) _check_access('package_update', context, data_dict) # get the schema package_plugin = lib_plugins.lookup_package_plugin(pkg.type) if 'schema' in context: schema = context['schema'] else: schema = package_plugin.update_package_schema() image_url = old_data.get('image_url', None) upload = uploader.Upload('edc', image_url) upload.update_data_dict(data_dict, 'image_url', 'image_upload', 'clear_upload') # Adding image display url for the uploaded image image_url = data_dict.get('image_url') data_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): image_url = munge.munge_filename(image_url) data_dict['image_display_url'] = h.url_for_static( 'uploads/edc/%s' % data_dict.get('image_url'), qualified=True) if 'api_version' not in context: # check_data_dict() is deprecated. If the package_plugin has a # check_data_dict() we'll call it, if it doesn't have the method we'll # do nothing. check_data_dict = getattr(package_plugin, 'check_data_dict', None) if check_data_dict: try: package_plugin.check_data_dict(data_dict, schema) except TypeError: # Old plugins do not support passing the schema so we need # to ensure they still work. package_plugin.check_data_dict(data_dict) # FIXME: modifications to package_update end here^ data, errors = lib_plugins.plugin_validate(package_plugin, context, data_dict, schema, 'package_update') log.debug('package_update validate_errs=%r user=%s package=%s data=%r', errors, context.get('user'), context.get('package').name if context.get('package') else '', data) if errors: model.Session.rollback() raise ValidationError(errors) rev = model.repo.new_revision() rev.author = user if 'message' in context: rev.message = context['message'] else: rev.message = _(u'REST API: Update object %s') % data.get("name") # avoid revisioning by updating directly model.Session.query(model.Package).filter_by(id=pkg.id).update( {"metadata_modified": datetime.datetime.utcnow()}) model.Session.refresh(pkg) pkg = model_save.package_dict_save(data, context) context_org_update = context.copy() context_org_update['ignore_auth'] = True context_org_update['defer_commit'] = True _get_action('package_owner_org_update')(context_org_update, { 'id': pkg.id, 'organization_id': pkg.owner_org }) for item in plugins.PluginImplementations(plugins.IPackageController): item.edit(pkg) item.after_update(context, data) upload.upload(uploader.get_max_image_size()) # TODO the next two blocks are copied from ckan/ckan/logic/action/update.py # This codebase is currently hard to maintain because large chunks of the # CKAN action API and the CKAN controllers are simply overriden. This is # probably worse than just forking CKAN would have been, because in that # case at least we could track changes. - @deniszgonjanin # Needed to let extensions know the new resources ids model.Session.flush() if data.get('resources'): for index, resource in enumerate(data['resources']): resource['id'] = pkg.resources[index].id # Create default views for resources if necessary if data.get('resources'): logic.get_action('package_create_default_resource_views')( { 'model': context['model'], 'user': context['user'], 'ignore_auth': True }, { 'package': data }) if not context.get('defer_commit'): model.repo.commit() log.debug('Updated object %s' % pkg.name) return_id_only = context.get('return_id_only', False) # Make sure that a user provided schema is not used on package_show context.pop('schema', None) # we could update the dataset so we should still be able to read it. context['ignore_auth'] = True output = data_dict['id'] if return_id_only \ else _get_action('package_show')(context, {'id': data_dict['id'], 'include_tracking':True}) ''' Send state change notifications if required; Added by Khalegh Mamakani Using a thread to run the job in the background so that package_update will not wait for notifications sending. ''' old_state = old_data.get('edc_state') context = { 'model': model, 'session': model.Session, 'user': c.user or c.author, 'auth_user_obj': c.userobj } dataset_url = config.get('ckan.site_url') + h.url_for( controller='package', action="read", id=data_dict['name']) import threading notify_thread = threading.Thread(target=check_record_state, args=(context, old_state, data_dict, g.site_title, g.site_url, dataset_url)) notify_thread.start() return output
def config_option_update(context, data_dict): ''' .. versionadded:: 2.4 Allows to modify some CKAN runtime-editable config options It takes arbitrary key, value pairs and checks the keys against the config options update schema. If some of the provided keys are not present in the schema a :py:class:`~ckan.plugins.logic.ValidationError` is raised. The values are then validated against the schema, and if validation is passed, for each key, value config option: * It is stored on the ``system_info`` database table * The Pylons ``config`` object is updated. * The ``app_globals`` (``g``) object is updated (this only happens for options explicitly defined in the ``app_globals`` module. The following lists a ``key`` parameter, but this should be replaced by whichever config options want to be updated, eg:: get_action('config_option_update)({}, { 'ckan.site_title': 'My Open Data site', 'ckan.homepage_layout': 2, }) :param key: a configuration option key (eg ``ckan.site_title``). It must be present on the ``update_configuration_schema`` :type key: string :returns: a dictionary with the options set :rtype: dictionary .. note:: You can see all available runtime-editable configuration options calling the :py:func:`~ckan.logic.action.get.config_option_list` action .. note:: Extensions can modify which configuration options are runtime-editable. For details, check :doc:`/extensions/remote-config-update`. .. warning:: You should only add config options that you are comfortable they can be edited during runtime, such as ones you've added in your own extension, or have reviewed the use of in core CKAN. ''' model = context['model'] _check_access('config_option_update', context, data_dict) schema = schema_.update_configuration_schema() available_options = schema.keys() provided_options = data_dict.keys() unsupported_options = set(provided_options) - set(available_options) if unsupported_options: msg = 'Configuration option(s) \'{0}\' can not be updated'.format( ' '.join(list(unsupported_options))) raise ValidationError(msg, error_summary={'message': msg}) upload = uploader.get_uploader('admin') upload.update_data_dict(data_dict, 'ckan.site_logo', 'logo_upload', 'clear_logo_upload') upload.upload(uploader.get_max_image_size()) data, errors = _validate(data_dict, schema, context) if errors: model.Session.rollback() raise ValidationError(errors) for key, value in data.iteritems(): # Set full Logo url if key == 'ckan.site_logo' and value and not value.startswith('http')\ and not value.startswith('/'): image_path = 'uploads/admin/' value = h.url_for_static('{0}{1}'.format(image_path, value)) # Save value in database model.set_system_info(key, value) # Update CKAN's `config` object config[key] = value # Only add it to the app_globals (`g`) object if explicitly defined # there globals_keys = app_globals.app_globals_from_config_details.keys() if key in globals_keys: app_globals.set_app_global(key, value) # Update the config update timestamp model.set_system_info('ckan.config_update', str(time.time())) log.info('Updated config options: {0}'.format(data)) return data
def group_dictize(group, context): result_dict = d.table_dictize(group, context) result_dict['display_name'] = group.display_name result_dict['extras'] = extras_dict_dictize( group._extras, context) include_datasets = context.get('include_datasets', True) q = { 'facet': 'false', 'rows': 0, } if group.is_organization: q['fq'] = 'owner_org:"{0}"'.format(group.id) else: q['fq'] = 'groups:"{0}"'.format(group.name) is_group_member = (context.get('user') and new_authz.has_user_permission_for_group_or_org(group.id, context.get('user'), 'read')) if is_group_member: context['ignore_capacity_check'] = True if include_datasets: q['rows'] = 1000 # Only the first 1000 datasets are returned context_ = dict((k, v) for (k, v) in context.items() if k != 'schema') search_results = logic.get_action('package_search')(context_, q) if include_datasets: result_dict['packages'] = search_results['results'] result_dict['package_count'] = search_results['count'] context['with_capacity'] = True result_dict['tags'] = tag_list_dictize( _get_members(context, group, 'tags'), context) result_dict['groups'] = group_list_dictize( _get_members(context, group, 'groups'), context) result_dict['users'] = user_list_dictize( _get_members(context, group, 'users'), context) context['with_capacity'] = False if context.get('for_view'): if result_dict['is_organization']: plugin = plugins.IOrganizationController else: plugin = plugins.IGroupController for item in plugins.PluginImplementations(plugin): result_dict = item.before_view(result_dict) image_url = result_dict.get('image_url') result_dict['image_display_url'] = image_url if image_url and not image_url.startswith('http'): #munge here should not have an effect only doing it incase #of potential vulnerability of dodgy api input image_url = munge.munge_filename(image_url) result_dict['image_display_url'] = h.url_for_static( 'uploads/group/%s' % result_dict.get('image_url'), qualified = True ) return result_dict
def test_url_for_static(self): url = "/assets/ckan.jpg" assert h.url_for_static(url) == url