Skip to content

Commit

Permalink
Merge branch 'master' into 788-facet-num-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
kindly committed Apr 23, 2013
2 parents 8a8dbdd + 1674cc4 commit 744ff97
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 67 deletions.
3 changes: 2 additions & 1 deletion ckan/lib/search/query.py
Expand Up @@ -16,7 +16,7 @@
_open_licenses = None

VALID_SOLR_PARAMETERS = set([
'q', 'fl', 'fq', 'rows', 'sort', 'start', 'wt', 'qf', 'bf',
'q', 'fl', 'fq', 'rows', 'sort', 'start', 'wt', 'qf', 'bf', 'boost',
'facet', 'facet.mincount', 'facet.limit', 'facet.field',
'extras', 'fq_list', 'tie', 'defType', 'mm'
])
Expand Down Expand Up @@ -353,6 +353,7 @@ def run(self, query):
query['mm'] = query.get('mm', '2<-1 5<80%')
query['qf'] = query.get('qf', QUERY_FIELDS)


conn = make_connection()
log.debug('Package query: %r' % query)
try:
Expand Down
11 changes: 11 additions & 0 deletions ckan/logic/__init__.py
Expand Up @@ -437,6 +437,17 @@ def get_converter(converter):
raise UnknownConverter('Converter `%s` does not exist' % converter)


def model_name_to_class(model_module, model_name):
'''Return the class in model_module that has the same name as the received string.
Raises AttributeError if there's no model in model_module named model_name.
'''
try:
model_class_name = model_name.title()
return getattr(model_module, model_class_name)
except AttributeError:
raise ValidationError("%s isn't a valid model" % model_class_name)

def _import_module_functions(module_path):
'''Import a module and get the functions and return them in a dict'''
functions_dict = {}
Expand Down
29 changes: 18 additions & 11 deletions ckan/logic/action/create.py
Expand Up @@ -418,28 +418,35 @@ def member_create(context, data_dict=None):
if 'message' in context:
rev.message = context['message']
else:
rev.message = _(u'REST API: Create member object %s') % data_dict.get("name", "")
rev.message = _(u'REST API: Create member object %s') % data_dict.get('name', '')

group = model.Group.get(data_dict.get('id', ''))
obj_id, obj_type, capacity = _get_or_bust(data_dict, ['object', 'object_type', 'capacity'])
group_id, obj_id, obj_type, capacity = _get_or_bust(data_dict, ['id', 'object', 'object_type', 'capacity'])

group = model.Group.get(group_id)
if not group:
raise NotFound('Group was not found.')

obj_class = ckan.logic.model_name_to_class(model, obj_type)
obj = obj_class.get(obj_id)
if not obj:
raise NotFound('%s was not found.' % obj_type.title())

# User must be able to update the group to add a member to it
_check_access('group_update', context, data_dict)

# Look up existing, in case it exists
member = model.Session.query(model.Member).\
filter(model.Member.table_name == obj_type).\
filter(model.Member.table_id == obj_id).\
filter(model.Member.table_id == obj.id).\
filter(model.Member.group_id == group.id).\
filter(model.Member.state == "active").first()
if member:
member.capacity = capacity
else:
filter(model.Member.state == 'active').first()
if not member:
member = model.Member(table_name = obj_type,
table_id = obj_id,
table_id = obj.id,
group_id = group.id,
state = 'active',
capacity=capacity)
state = 'active')

member.capacity = capacity

model.Session.add(member)
model.repo.commit()
Expand Down
18 changes: 13 additions & 5 deletions ckan/logic/action/delete.py
Expand Up @@ -168,7 +168,7 @@ def member_delete(context, data_dict=None):
:param id: the id of the group
:type id: string
:param object: the id of the object to be removed
:param object: the id or name of the object to be removed
:type object: string
:param object_type: the type of the object to be removed, e.g. ``package``
or ``user``
Expand All @@ -177,17 +177,25 @@ def member_delete(context, data_dict=None):
'''
model = context['model']

group = model.Group.get(_get_or_bust(data_dict, 'id'))
obj_id, obj_type = _get_or_bust(data_dict, ['object', 'object_type'])
group_id, obj_id, obj_type = _get_or_bust(data_dict, ['id', 'object', 'object_type'])

group = model.Group.get(group_id)
if not group:
raise NotFound('Group was not found.')

obj_class = ckan.logic.model_name_to_class(model, obj_type)
obj = obj_class.get(obj_id)
if not obj:
raise NotFound('%s was not found.' % obj_type.title())

# User must be able to update the group to remove a member from it
_check_access('group_update', context, data_dict)

member = model.Session.query(model.Member).\
filter(model.Member.table_name == obj_type).\
filter(model.Member.table_id == obj_id).\
filter(model.Member.table_id == obj.id).\
filter(model.Member.group_id == group.id).\
filter(model.Member.state == "active").first()
filter(model.Member.state == 'active').first()
if member:
rev = model.repo.new_revision()
rev.author = context.get('user')
Expand Down
34 changes: 27 additions & 7 deletions ckan/logic/action/get.py
Expand Up @@ -1156,26 +1156,22 @@ def package_search(context, data_dict):
This action accepts a *subset* of solr's search query parameters:
:param q: the solr query. Optional. Default: `"*:*"`
:type q: string
:param fq: any filter queries to apply. Note: `+site_id:{ckan_site_id}`
is added to this string prior to the query being executed.
:type fq: string
:param rows: the number of matching rows to return.
:type rows: int
:param sort: sorting of the search results. Optional. Default:
'relevance asc, metadata_modified desc'. As per the solr
documentation, this is a comma-separated string of field names and
sort-orderings.
:type sort: string
:param rows: the number of matching rows to return.
:type rows: int
:param start: the offset in the complete result for where the set of
returned datasets should begin.
:type start: int
:param qf: the dismax query fields to search within, including boosts. See
the `Solr Dismax Documentation
<http://wiki.apache.org/solr/DisMaxQParserPlugin#qf_.28Query_Fields.29>`_
for further details.
:type qf: string
:param facet: whether to enable faceted results. Default: "true".
:type facet: string
:param facet.mincount: the minimum counts for facet fields should be
Expand All @@ -1188,6 +1184,18 @@ def package_search(context, data_dict):
then the returned facet information is empty.
:type facet.field: list of strings
The following advanced Solr parameters are supported as well. Note that
some of these are only available on particular Solr versions. See Solr's
`dismax`_ and `edismax`_ documentation for further details on them:
``qf``, ``wt``, ``bf``, ``boost``, ``tie``, ``defType``, ``mm``
.. _dismax: http://wiki.apache.org/solr/DisMaxQParserPlugin
.. _edismax: http://wiki.apache.org/solr/ExtendedDisMax
**Results:**
The result of this action is a dict with the following keys:
Expand Down Expand Up @@ -1239,6 +1247,12 @@ def package_search(context, data_dict):

_check_access('package_search', context, data_dict)

# Move ext_ params to extras and remove them from the root of the search
# params, so they don't cause and error
data_dict['extras'] = data_dict.get('extras', {})
for key in [key for key in data_dict.keys() if key.startswith('ext_')]:
data_dict['extras'][key] = data_dict.pop(key)

# check if some extension needs to modify the search params
for item in plugins.PluginImplementations(plugins.IPackageController):
data_dict = item.before_search(data_dict)
Expand All @@ -1265,9 +1279,15 @@ def package_search(context, data_dict):
if not 'capacity:' in p)
data_dict['fq'] = fq + ' capacity:"public"'

# Pop these ones as Solr does not need them
extras = data_dict.pop('extras', None)

query = search.query_for(model.Package)
query.run(data_dict)

# Add them back so extensions can use them on after_search
data_dict['extras'] = extras

for package in query.results:
# get the package object
package, package_dict = package['id'], package.get('data_dict')
Expand Down
2 changes: 0 additions & 2 deletions ckan/templates/package/snippets/data_api_button.html
Expand Up @@ -8,6 +8,4 @@
{% set loading_text = _('Loading...') %}
{% set api_info_url = h.url_for(controller='api', action='snippet', ver=1, snippet_path='api_info.html', datastore_root_url=datastore_root_url, resource_id=resource.id) %}
<a class="btn btn-success" href="{{ api_info_url }}" data-module="api-info" data-module-template="{{ api_info_url }}" data-loading-text="{{ loading_text }}"><i class="icon-beaker icon-large"></i> {{ _('Data API') }}</a>
{% else %}
<a class="btn disabled" rel="tooltip" title="{{ _('Data API is unavailable for this resource as no data has been pushed to it yet') }}"><i class="icon-beaker icon-large"></i> {{ _('Data API') }}</a>
{% endif %}
10 changes: 10 additions & 0 deletions ckan/tests/logic/test_init.py
@@ -0,0 +1,10 @@
import nose.tools as tools

import ckan.model as model
import ckan.logic as logic


class TestMemberLogic(object):
def test_model_name_to_class(self):
assert logic.model_name_to_class(model, 'package') == model.Package
tools.assert_raises(logic.ValidationError, logic.model_name_to_class, model, 'inexistent_model_name')

0 comments on commit 744ff97

Please sign in to comment.