Skip to content

Commit

Permalink
Merge branch 'master' into enhancement-2371-fanstatic
Browse files Browse the repository at this point in the history
  • Loading branch information
tobes committed May 8, 2012
2 parents de258ae + 20d06d6 commit f8be532
Show file tree
Hide file tree
Showing 34 changed files with 745 additions and 614 deletions.
26 changes: 18 additions & 8 deletions ckan/authz.py
Expand Up @@ -154,13 +154,23 @@ def get_roles(cls, username, domain_obj):
return [pr.role for pr in q]

@classmethod
def is_sysadmin(cls, username):
user = model.User.by_name(username, autoflush=False)
if user:
q = model.Session.query(model.SystemRole)
q = q.autoflush(False)
q = q.filter_by(role=model.Role.ADMIN, user=user)
return q.count() > 0
def is_sysadmin(cls, user):
'''Returns whether the given user a sys-admin?
(sysadmin = system administrator with full authorization)
Ideally provide a user object. Next best is a user name.
'''
if not user:
return False
if isinstance(user, basestring):
user = model.User.by_name(user, autoflush=False)
if not user:
return False
elif not isinstance(user, model.User):
raise NotImplementedError
q = model.Session.query(model.SystemRole)
q = q.autoflush(False)
q = q.filter_by(role=model.Role.ADMIN, user=user)
return q.count() > 0

@classmethod
def get_admins(cls, domain_obj):
Expand Down Expand Up @@ -188,7 +198,7 @@ def authorized_query(cls, username, entity, action=model.Action.READ):
visitor = model.User.by_name(model.PSEUDO_USER__VISITOR, autoflush=False)
logged_in = model.User.by_name(model.PSEUDO_USER__LOGGED_IN,
autoflush=False)
if not cls.is_sysadmin(username):
if not cls.is_sysadmin(user):
# This gets the role table the entity is joined to. we
# need to use this in the queries below as if we use
# model.UserObjectRole a cross join happens always
Expand Down
2 changes: 2 additions & 0 deletions ckan/controllers/admin.py
Expand Up @@ -234,6 +234,8 @@ def action_add_form(users_or_authz_groups):
c.authz_groups = authz_groups
c.authz_groups_role_dict = authz_groups_role_dict

c.are_any_authz_groups = bool(model.Session.query(model.AuthorizationGroup).count())

return render('admin/authz.html')

def trash(self):
Expand Down
2 changes: 1 addition & 1 deletion ckan/controllers/api.py
Expand Up @@ -591,7 +591,7 @@ def group_autocomplete(self):
limit = 20
limit = min(50, limit)

query = model.Group.search_by_name(q, t)
query = model.Group.search_by_name_or_title(q, t)
def convert_to_dict(user):
out = {}
for k in ['id', 'name', 'title']:
Expand Down
8 changes: 5 additions & 3 deletions ckan/controllers/related.py
Expand Up @@ -18,17 +18,19 @@ def list(self, id):

try:
logic.check_access('package_show', context, data_dict)
except logic.NotFound:
base.abort(404, base._('Dataset not found'))
except logic.NotAuthorized:
abort(401, _('Not authorized to see this page'))
base.abort(401, base._('Not authorized to see this page'))

try:
c.pkg_dict = logic.get_action('package_show')(context, data_dict)
c.pkg = context['package']
c.resources_json = h.json.dumps(c.pkg_dict.get('resources',[]))
except logic.NotFound:
abort(404, _('Dataset not found'))
base.abort(404, base._('Dataset not found'))
except logic.NotAuthorized:
abort(401, _('Unauthorized to read package %s') % id)
base.abort(401, base._('Unauthorized to read package %s') % id)

c.related_count = len(c.pkg.related)

Expand Down
2 changes: 1 addition & 1 deletion ckan/lib/base.py
Expand Up @@ -541,7 +541,7 @@ def _prepare_authz_info_for_render(self, user_object_roles):
c.user_role_dict = user_role_dict
c.authz_groups = authz_groups
c.authz_groups_role_dict = authz_groups_role_dict

c.are_any_authz_groups = bool(model.Session.query(model.AuthorizationGroup).count())

# Include the '_' function in the public names
__all__ = [__name for __name in locals().keys() if not __name.startswith('_') \
Expand Down
62 changes: 62 additions & 0 deletions ckan/lib/create_test_data.py
Expand Up @@ -628,6 +628,68 @@ def reset(cls):
def get_all_data(cls):
return cls.pkg_names + list(cls.group_names) + cls.tag_names + cls.user_refs

@classmethod
def make_some_vocab_tags(cls):
import ckan.model as model
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 additional free tags for tag search tests.
tolkien_tag = model.Tag(name="tolkien")
model.Session.add(tolkien_tag)
toledo_tag = model.Tag(name="toledo")
model.Session.add(toledo_tag)
tolerance_tag = model.Tag(name="tolerance")
model.Session.add(tolerance_tag)
tollbooth_tag = model.Tag(name="tollbooth")
model.Session.add(tollbooth_tag)
# We have to add free tags to a package or they won't show up in tag results.
model.Package.get('warandpeace').add_tags((tolkien_tag, toledo_tag,
tolerance_tag, tollbooth_tag))

# 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)

model.Session.commit()



search_items = [{'name':'gils',
'title':'Government Information Locator Service',
Expand Down
4 changes: 2 additions & 2 deletions ckan/lib/mailer.py
Expand Up @@ -48,15 +48,15 @@ def _mail_recipient(recipient_name, recipient_email,
log.exception(msg)
raise MailerException(msg)

def mail_recipient(recipient_name, recipient_email, subject,
def mail_recipient(recipient_name, recipient_email, subject,
body, headers={}):
return _mail_recipient(recipient_name, recipient_email,
g.site_title, g.site_url, subject, body, headers=headers)

def mail_user(recipient, subject, body, headers={}):
if (recipient.email is None) or not len(recipient.email):
raise MailerException(_("No recipient email address available!"))
mail_recipient(recipient.display_name, recipient.email, subject,
mail_recipient(recipient.display_name, recipient.email, subject,
body, headers=headers)


Expand Down
5 changes: 3 additions & 2 deletions ckan/logic/action/create.py
Expand Up @@ -11,6 +11,7 @@
import ckan.lib.dictization.model_dictize as model_dictize
import ckan.lib.dictization.model_save as model_save
import ckan.lib.navl.dictization_functions
import ckan.logic.auth as auth

# FIXME this looks nasty and should be shared better
from ckan.logic.action.update import _update_package_relationship
Expand Down Expand Up @@ -196,15 +197,14 @@ def member_create(context, data_dict=None):
user - The name of the current user
data_dict:
group - The ID of the group to which we want to add a new object
id - The ID of the group to which we want to add a new object
object - The ID of the object being added as a member
object_type - The name of the type being added, all lowercase,
e.g. package, or user
capacity - The capacity with which to add this object
"""
model = context['model']
user = context['user']
group = context['group']

rev = model.repo.new_revision()
rev.author = user
Expand All @@ -213,6 +213,7 @@ def member_create(context, data_dict=None):
else:
rev.message = _(u'REST API: Create member object %s') % data_dict.get("name", "")

group = model.Group.get(data_dict.get('id', ''))
obj_id = data_dict['object']
obj_type = data_dict['object_type']
capacity = data_dict['capacity']
Expand Down
5 changes: 2 additions & 3 deletions ckan/logic/action/delete.py
Expand Up @@ -90,16 +90,15 @@ def member_delete(context, data_dict=None):
user - The name of the current user
data_dict:
group - The ID of the group to which we want to remove object
id - The ID of the group from which we want to remove object
object - The ID of the object being removed as a member
object_type - The name of the type being removed, all lowercase,
e.g. package, or user
"""
model = context['model']
user = context['user']
group = context['group']

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

Expand Down
22 changes: 12 additions & 10 deletions ckan/logic/action/get.py
Expand Up @@ -179,16 +179,15 @@ def member_list(context, data_dict=None):
user - The name of the current user
data_dict:
group - The ID of the group to which we want to list members
id - The ID of the group to which we want to list members
object_type - The optional name of the type being added, all lowercase,
e.g. package, or user
capacity - The optional capacity of objects that we want to retrieve
"""
model = context['model']
user = context['user']
group = context['group']

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

Expand Down Expand Up @@ -322,7 +321,7 @@ def tag_list(context, data_dict):
check_access('tag_list', context, data_dict)

if query:
tags = _tag_search(context, data_dict)
tags, count = _tag_search(context, data_dict)
else:
tags = model.Tag.all(vocab_id_or_name)

Expand Down Expand Up @@ -922,7 +921,8 @@ def resource_search(context, data_dict):
return {'count': count, 'results': results}

def _tag_search(context, data_dict):
'''Return a list of tag objects that contain the given string.
'''Return a list of tag objects that contain the given string and
the full count (for paging).
The query string should be provided in the data_dict with key 'query' or
'q'.
Expand All @@ -931,6 +931,7 @@ def _tag_search(context, data_dict):
searched. If a 'vocabulary_id' is provided in the data_dict then tags
belonging to the given vocabulary (id or name) will be searched instead.
Use 'offset' and 'limit' parameters to page through results.
'''
model = context['model']

Expand Down Expand Up @@ -964,15 +965,16 @@ def _tag_search(context, data_dict):
terms.append(value)

if not len(terms):
return []
return [], 0

for term in terms:
escaped_term = misc.escape_sql_like_special_characters(term, escape='\\')
q = q.filter(model.Tag.name.ilike('%' + escaped_term + '%'))

count = q.count()
q = q.offset(offset)
q = q.limit(limit)
return q.all()
return q.all(), count

def tag_search(context, data_dict):
'''Return a list of tag dictionaries that contain the given string.
Expand All @@ -988,8 +990,8 @@ def tag_search(context, data_dict):
and 'results' (the list of tag dicts).
'''
tags = _tag_search(context, data_dict)
return {'count': len(tags),
tags, count = _tag_search(context, data_dict)
return {'count': count,
'results': [table_dictize(tag, context) for tag in tags]}

def tag_autocomplete(context, data_dict):
Expand All @@ -1004,7 +1006,7 @@ def tag_autocomplete(context, data_dict):
'''
check_access('tag_autocomplete', context, data_dict)
matching_tags = _tag_search(context, data_dict)
matching_tags, count = _tag_search(context, data_dict)
if matching_tags:
return [tag.name for tag in matching_tags]
else:
Expand Down
12 changes: 7 additions & 5 deletions ckan/model/group.py
Expand Up @@ -9,6 +9,7 @@
import vdm.sqlalchemy
from ckan.model import extension, User
from sqlalchemy.ext.associationproxy import association_proxy
import sqlalchemy as sa

__all__ = ['group_table', 'Group', 'package_revision_table',
'Member', 'GroupRevision', 'MemberRevision',
Expand Down Expand Up @@ -181,12 +182,13 @@ def active_packages(self, load_eager=True, with_private=False):
return query

@classmethod
def search_by_name(cls, text_query, group_type=None):
def search_by_name_or_title(cls, text_query, group_type=None):
text_query = text_query.strip().lower()
if not group_type:
q = Session.query(cls).filter(cls.name.contains(text_query))
else:
q = Session.query(cls).filter(cls.name.contains(text_query)).filter(cls.type==group_type)
q = Session.query(cls) \
.filter(sa.or_(cls.name.contains(text_query),
cls.title.ilike('%' + text_query + '%')))
if group_type:
q = q.filter(cls.type==group_type)
return q.order_by(cls.title)

def as_dict(self, ref_package_by='name'):
Expand Down
8 changes: 4 additions & 4 deletions ckan/plugins/toolkit.py
Expand Up @@ -16,15 +16,15 @@ class CkanVersionException(Exception):

class _Toolkit(object):
'''This class is intended to make functions/objects consistently
available to plugins, whilst giving developers the ability move
available to plugins, whilst giving core CKAN developers the ability move
code around or change underlying frameworks etc. This object allows
us to avoid circular imports while making functions/objects
available to plugins.
It should not be used internally within ckan only by extensions.
It should not be used internally within ckan - only by extensions.
Functions/objects should only be removed after reasonable
depreciation notice has been given.'''
deprecation notice has been given.'''

# contents should describe the available functions/objects. We check
# that this list matches the actual availables in the initialisation
Expand Down Expand Up @@ -175,7 +175,7 @@ def _requires_ckan_version(cls, min_version, max_version=None):
if not max_version:
error = 'Requires ckan version %s or higher' % min_version
else:
error = 'Requires ckan version between %s and %s' % \
error = 'Requires ckan version between %s and %s' % \
(min_version, max_version)
raise cls.CkanVersionException(error)

Expand Down

0 comments on commit f8be532

Please sign in to comment.