Skip to content

Commit

Permalink
Merge branch 'feature-1698-tag-taxonomies' of github.com:okfn/ckan in…
Browse files Browse the repository at this point in the history
…to feature-1698-tag-taxonomies
  • Loading branch information
johnglover committed Feb 14, 2012
2 parents a0a2d67 + a08f209 commit 03f03ff
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 26 deletions.
40 changes: 19 additions & 21 deletions ckan/logic/action/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,27 +609,13 @@ def package_autocomplete(context, data_dict):

def tag_autocomplete(context, data_dict):
'''Returns tags containing the provided string'''

model = context['model']
session = context['session']
user = context['user']

check_access('tag_autocomplete', context, data_dict)

q = data_dict.get('q', None)
if not q:
matching_tags = tag_search(context, data_dict)
if matching_tags:
return [tag.name for tag in matching_tags['results']]
else:
return []

limit = data_dict.get('limit',10)

query = query_for('tag')
query.run(query=q,
return_objects=True,
limit=10,
username=user)

return [tag.name for tag in query.results]

def format_autocomplete(context, data_dict):
'''Returns formats containing the provided string'''
model = context['model']
Expand Down Expand Up @@ -819,9 +805,8 @@ def resource_search(context, data_dict):

def tag_search(context, data_dict):
model = context['model']
session = context['session']

query = data_dict.get('query')
query = data_dict.get('query') or data_dict.get('q')
terms = [query] if query else []

fields = data_dict.get('fields', {})
Expand All @@ -830,7 +815,20 @@ def tag_search(context, data_dict):

# TODO: should we check for user authentication first?
q = model.Session.query(model.Tag)
q = q.distinct().join(model.Tag.package_tags)

if data_dict.has_key('vocabulary_name'):
# Filter by vocabulary.
vocab = model.Vocabulary.get(data_dict['vocabulary_name'])
if not vocab:
raise NotFound
q = q.filter(model.Tag.vocabulary_id == vocab.id)
else:
# If no vocabulary_name in data dict then show free tags only.
q = q.filter(model.Tag.vocabulary_id == None)
# If we're searching free tags, limit results to tags that are
# currently applied to a package.
q = q.distinct().join(model.Tag.package_tags)

for field, value in fields.items():
if field in ('tag', 'tags'):
terms.append(value)
Expand Down
2 changes: 1 addition & 1 deletion ckan/model/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def all(cls, vocab_id_or_name=None):
return None
query = Session.query(Tag).filter(Tag.vocabulary_id==vocab.id)
else:
query = Session.query(Tag)
query = Session.query(Tag).filter(Tag.vocabulary_id == None)
query = query.distinct().join(PackageTagRevision)
query = query.filter(sqlalchemy.and_(
PackageTagRevision.state == 'active',
Expand Down
103 changes: 99 additions & 4 deletions ckan/tests/logic/test_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,61 @@ class TestAction(WsgiAppCase):
normal_user = None

@classmethod
def setup_class(self):
def setup_class(cls):
CreateTestData.create()
self.sysadmin_user = model.User.get('testsysadmin')
self.normal_user = model.User.get('annafan')
cls.sysadmin_user = model.User.get('testsysadmin')
cls.normal_user = model.User.get('annafan')
cls.make_some_vocab_tags()

@classmethod
def teardown_class(self):
def teardown_class(cls):
model.repo.rebuild_db()

@classmethod
def make_some_vocab_tags(cls):
model.repo.new_revision()

# Create a couple of vocabularies.
genre_vocab = model.Vocabulary(u'genre')
model.Session.add(genre_vocab)
composers_vocab = model.Vocabulary(u'composers')
model.Session.add(composers_vocab)

# Create some tags that belong to vocabularies.
sonata_tag = model.Tag(name=u'sonata', vocabulary_id=genre_vocab.id)
model.Session.add(sonata_tag)

bach_tag = model.Tag(name=u'Bach', vocabulary_id=composers_vocab.id)
model.Session.add(bach_tag)

neoclassical_tag = model.Tag(name='neoclassical',
vocabulary_id=genre_vocab.id)
model.Session.add(neoclassical_tag)

neofolk_tag = model.Tag(name='neofolk', vocabulary_id=genre_vocab.id)
model.Session.add(neofolk_tag)

neomedieval_tag = model.Tag(name='neomedieval',
vocabulary_id=genre_vocab.id)
model.Session.add(neomedieval_tag)

neoprog_tag = model.Tag(name='neoprog',
vocabulary_id=genre_vocab.id)
model.Session.add(neoprog_tag)

neopsychedelia_tag = model.Tag(name='neopsychedelia',
vocabulary_id=genre_vocab.id)
model.Session.add(neopsychedelia_tag)

neosoul_tag = model.Tag(name='neosoul', vocabulary_id=genre_vocab.id)
model.Session.add(neosoul_tag)

nerdcore_tag = model.Tag(name='nerdcore', vocabulary_id=genre_vocab.id)
model.Session.add(nerdcore_tag)

model.Package.get('warandpeace').add_tag(bach_tag)
model.Package.get('annakarenina').add_tag(sonata_tag)

def _add_basic_package(self, package_name=u'test_package', **kwargs):
package = {
'name': package_name,
Expand Down Expand Up @@ -827,6 +873,55 @@ def test_15_tag_autocomplete_is_case_insensitive(self):
assert res_obj['success']
assert 'MIX of CAPITALS and LOWER case' in res_obj['result'], res_obj['result']

def test_15_tag_autocomplete_with_vocab_and_empty_query(self):
for q in ('missing', None, '', ' '):
paramd = {'vocabulary_name': u'genre'}
if q != 'missing':
paramd['q'] = q
params = json.dumps(paramd)
res = self.app.post('/api/action/tag_autocomplete', params=params)
assert res.json['success'] is True
assert res.json['result'] == []

def test_15_tag_autocomplete_with_vocab_and_single_match(self):
paramd = {'vocabulary_name': u'genre', 'q': 'son'}
params = json.dumps(paramd)
res = self.app.post('/api/action/tag_autocomplete', params=params)
assert res.json['success'] is True
assert res.json['result'] == ['sonata'], res.json['result']

def test_15_tag_autocomplete_with_vocab_and_multiple_matches(self):
paramd = {'vocabulary_name': 'genre', 'q': 'neo'}
params = json.dumps(paramd)
res = self.app.post('/api/action/tag_autocomplete', params=params)
assert res.json['success'] is True
assert res.json['result'] == ['neoclassical', 'neofolk', 'neomedieval',
'neoprog', 'neopsychedelia', 'neosoul'], res.json['result']

def test_15_tag_autocomplete_with_vocab_and_no_matches(self):
paramd = {'vocabulary_name': 'composers', 'q': 'Jonny Greenwood'}
params = json.dumps(paramd)
res = self.app.post('/api/action/tag_autocomplete', params=params)
assert res.json['success'] is True
assert res.json['result'] == []

def test_15_tag_autocomplete_with_vocab_that_does_not_exist(self):
for q in ('', 'neo'):
paramd = {'vocabulary_name': 'does_not_exist', 'q': q}
params = json.dumps(paramd)
res = self.app.post('/api/action/tag_autocomplete', params=params,
status=404)
assert res.json['success'] is False

def test_15_tag_autocomplete_with_invalid_vocab(self):
for vocab_name in (None, '', 'a', 'e'*200):
for q in (None, '', 'son'):
paramd = {'vocabulary_name': vocab_name, 'q': q}
params = json.dumps(paramd)
res = self.app.post('/api/action/tag_autocomplete', params=params,
status=404)
assert res.json['success'] is False

def test_16_user_autocomplete(self):
#Empty query
postparams = '%s=1' % json.dumps({})
Expand Down

0 comments on commit 03f03ff

Please sign in to comment.