Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/okfn/ckan
Browse files Browse the repository at this point in the history
  • Loading branch information
rossjones committed Mar 12, 2012
2 parents 2f6ef03 + 476a5bd commit 4ff47f9
Show file tree
Hide file tree
Showing 74 changed files with 9,170 additions and 3,155 deletions.
4 changes: 2 additions & 2 deletions README.rst
Expand Up @@ -9,8 +9,8 @@ http://ckan.org/.
* Developer mailing list: ckan-dev@lists.okfn.org
* Issue tracker: http://trac.ckan.org/

Building Documentation
======================
Building Documentation
======================

1. Install python-sphinx

Expand Down
5 changes: 5 additions & 0 deletions ckan/config/deployment.ini_tmpl
Expand Up @@ -111,6 +111,11 @@ ckan.site_url =
## Favicon (default is the CKAN software favicon)
ckan.favicon = /images/icons/ckan.ico

## The gravatar default to use. This can be any of the pre-defined strings
## as defined on http://en.gravatar.com/site/implement/images/ (e.g. "identicon"
## or "mm"). Or it can be a url, e.g. "http://example.com/images/avatar.jpg"
ckan.gravatar_default = identicon

## Solr support
#solr_url = http://127.0.0.1:8983/solr

Expand Down
3 changes: 3 additions & 0 deletions ckan/config/routing.py
Expand Up @@ -115,6 +115,8 @@ def make_map():
conditions=GET)
m.connect('/util/resource/format_autocomplete',
action='format_autocomplete', conditions=GET)
m.connect('/util/resource/format_icon',
action='format_icon', conditions=GET)
m.connect('/util/authorizationgroup/autocomplete',
action='authorizationgroup_autocomplete')
m.connect('/util/group/autocomplete', action='group_autocomplete')
Expand Down Expand Up @@ -175,6 +177,7 @@ def make_map():
m.connect('/dataset/{action}/{id}',
requirements=dict(action='|'.join([
'edit',
'editresources',
'authz',
'history',
'read_ajax',
Expand Down
10 changes: 9 additions & 1 deletion ckan/controllers/api.py
Expand Up @@ -5,7 +5,7 @@
from webob.multidict import UnicodeMultiDict

from ckan.lib.base import BaseController, response, c, _, gettext, request
from ckan.lib.helpers import json, date_str_to_datetime
from ckan.lib.helpers import json, date_str_to_datetime, format_icon, icon_url
import ckan.model as model
import ckan.rating
from ckan.lib.search import (query_for, QueryOptions, SearchIndexError, SearchError,
Expand Down Expand Up @@ -692,6 +692,14 @@ def munge_tag(self):
munged_tag = munge_tag(tag)
return self._finish_ok(munged_tag)

def format_icon(self):
f = request.params.get('format')
out = {
'format' : f,
'icon' : icon_url(format_icon(f))
}
return self._finish_ok(out)

def status(self):
context = {'model': model, 'session': model.Session}
data_dict = {}
Expand Down
12 changes: 12 additions & 0 deletions ckan/controllers/datastore.py
@@ -1,5 +1,7 @@
from ckan.lib.base import BaseController, abort, _, c, response, request, g
import ckan.model as model
from ckan.lib.helpers import json
from ckan.lib.jsonp import jsonpify
from ckan.logic import get_action, check_access
from ckan.logic import NotFound, NotAuthorized, ValidationError

Expand All @@ -11,26 +13,36 @@ def _make_redirect(self, id, url=''):
# headers must be ascii strings
response.headers['X-Accel-Redirect'] = str(redirect)

@jsonpify
def read(self, id, url=''):
context = {'model': model, 'session': model.Session,
'user': c.user or c.author}

try:
resource = get_action('resource_show')(context, {'id': id})
if not resource.get('webstore_url', ''):
return {
'error': 'DataStore is disabled for this resource'
}
self._make_redirect(id, url)
return ''
except NotFound:
abort(404, _('Resource not found'))
except NotAuthorized:
abort(401, _('Unauthorized to read resource %s') % id)

@jsonpify
def write(self, id, url):
context = {'model': model, 'session': model.Session,
'user': c.user or c.author}
try:
resource = model.Resource.get(id)
if not resource:
abort(404, _('Resource not found'))
if not resource.webstore_url:
return {
'error': 'DataStore is disabled for this resource'
}
context["resource"] = resource
check_access('resource_update', context, {'id': id})
self._make_redirect(id, url)
Expand Down
27 changes: 6 additions & 21 deletions ckan/controllers/group.py
Expand Up @@ -18,7 +18,6 @@

log = logging.getLogger(__name__)


class GroupController(BaseController):

## hooks for subclasses
Expand Down Expand Up @@ -244,28 +243,14 @@ def edit(self, id, data=None, errors=None, error_summary=None):

def _get_group_type(self, id):
"""
Given the id of a group it determines the plugin to load
based on the group's type name (type). The plugin found
will be returned, or None if there is no plugin associated with
the type.
Uses a minimal context to do so. The main use of this method
is for figuring out which plugin to delegate to.
aborts if an exception is raised.
Given the id of a group it determines the type of a group given
a valid id/name for the group.
"""
global _controller_behaviour_for

context = {'model': model, 'session': model.Session,
'user': c.user or c.author}
try:
data = get_action('group_show')(context, {'id': id})
except NotFound:
abort(404, _('Group not found'))
except NotAuthorized:
abort(401, _('Unauthorized to read group %s') % id)
return data['type']
group = model.Group.get( id )
if not group:
return None

return group.type

def _save_new(self, context, group_type=None):
try:
Expand Down
25 changes: 14 additions & 11 deletions ckan/controllers/package.py
Expand Up @@ -321,10 +321,12 @@ def new(self, data=None, errors=None, error_summary=None):

data = data or clean_dict(unflatten(tuplize_dict(parse_params(
request.params, ignore_keys=[CACHE_PARAMETER]))))
c.pkg_json = json.dumps(data)

errors = errors or {}
error_summary = error_summary or {}
vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
c.errors_json = json.dumps(errors)

self._setup_template_variables(context, {'id': id})

Expand Down Expand Up @@ -370,6 +372,7 @@ def edit(self, id, data=None, errors=None, error_summary=None):

errors = errors or {}
vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
c.errors_json = json.dumps(errors)

self._setup_template_variables(context, {'id': id}, package_type=package_type)

Expand All @@ -379,7 +382,15 @@ def edit(self, id, data=None, errors=None, error_summary=None):
c.form = render(self.package_form, extra_vars=vars)
else:
c.form = render(self._package_form(package_type=package_type), extra_vars=vars)
return render('package/edit.html')

if (c.action == u'editresources'):
return render('package/editresources.html')
else:
return render('package/edit.html')

def editresources(self, id, data=None, errors=None, error_summary=None):
'''Hook method made available for routing purposes.'''
return self.edit(id,data,errors,error_summary)

def read_ajax(self, id, revision=None):
package_type=self._get_package_type(id)
Expand Down Expand Up @@ -450,8 +461,6 @@ def _get_package_type(self, id):
aborts if an exception is raised.
"""
global _controller_behaviour_for

context = {'model': model, 'session': model.Session,
'user': c.user or c.author}
try:
Expand Down Expand Up @@ -523,13 +532,6 @@ def _form_save_redirect(self, pkgname, action):
@param action - What the action of the edit was
'''
assert action in ('new', 'edit')
if action == 'new':
msg = _('<span class="new-dataset">Congratulations, your dataset has been created. ' \
'<a href="%s">Upload or link ' \
'some data now &raquo;</a></span>')
msg = msg % h.url_for(controller='package', action='edit',
id=pkgname, anchor='section-resources')
h.flash_success(msg,allow_html=True)
url = request.params.get('return_to') or \
config.get('package_%s_return_url' % action)
if url:
Expand Down Expand Up @@ -660,6 +662,7 @@ def resource_read(self, id, resource_id):
c.package['isopen'] = model.Package.get_license_register()[license_id].isopen()
except KeyError:
c.package['isopen'] = False

c.datastore_api = h.url_for('datastore_read', id=c.resource.get('id'),
qualified=True)
return render('package/resource_read.html')

20 changes: 10 additions & 10 deletions ckan/controllers/user.py
Expand Up @@ -11,7 +11,7 @@
from ckan.logic import NotFound, NotAuthorized, ValidationError
from ckan.logic import check_access, get_action
from ckan.logic import tuplize_dict, clean_dict, parse_params
from ckan.logic.schema import user_new_form_schema, user_edit_form_schema
from ckan.logic.schema import user_new_form_schema, user_edit_form_schema
from ckan.logic.action.get import user_activity_list_html
from ckan.lib.captcha import check_recaptcha, CaptchaError

Expand All @@ -28,7 +28,7 @@ def __before__(self, action, **env):
if c.action not in ('login','request_reset','perform_reset',):
abort(401, _('Not authorized to see this page'))

## hooks for subclasses
## hooks for subclasses
new_user_form = 'user/new_user_form.html'
edit_user_form = 'user/edit_user_form.html'

Expand Down Expand Up @@ -207,10 +207,10 @@ def edit(self, id=None, data=None, errors=None, error_summary=None):
abort(404, _('User not found'))

user_obj = context.get('user_obj')

if not (ckan.authz.Authorizer().is_sysadmin(unicode(c.user)) or c.user == user_obj.name):
abort(401, _('User %s not authorized to edit %s') % (str(c.user), id))

errors = errors or {}
vars = {'data': data, 'errors': errors, 'error_summary': error_summary}

Expand Down Expand Up @@ -255,7 +255,7 @@ def login(self):
return render('user/login.html')
else:
return render('user/logout_first.html')

def logged_in(self):
if c.user:
context = {'model': model,
Expand All @@ -277,14 +277,14 @@ def logged_in(self):
h.flash_error('Login failed. Bad username or password.' + \
' (Or if using OpenID, it hasn\'t been associated with a user account.)')
h.redirect_to(controller='user', action='login')

def logged_out(self):
c.user = None
response.delete_cookie("ckan_user")
response.delete_cookie("ckan_display_name")
response.delete_cookie("ckan_apikey")
return render('user/logout.html')

def request_reset(self):
if request.method == 'POST':
id = request.params.get('user')
Expand Down Expand Up @@ -346,7 +346,7 @@ def perform_reset(self, id):

if request.method == 'POST':
try:
context['reset_password'] = True
context['reset_password'] = True
new_password = self._get_form_password()
user_dict['password'] = new_password
user_dict['reset_key'] = c.reset_key
Expand Down Expand Up @@ -374,7 +374,7 @@ def _format_about(self, about):
log.error('Could not print "about" field Field: %r Error: %r', about, e)
html = _('Error: Could not parse About text')
return html

def _get_form_password(self):
password1 = request.params.getone('password1')
password2 = request.params.getone('password2')
Expand All @@ -384,4 +384,4 @@ def _get_form_password(self):
elif not password1 == password2:
raise ValueError(_("The passwords you entered do not match."))
return password1

9 changes: 6 additions & 3 deletions ckan/lib/alphabet_paginate.py
Expand Up @@ -45,11 +45,14 @@ def __init__(self, collection, alpha_attribute, page, other_text, paging_thresho
self.controller_name = controller_name
self.available = dict( (c,0,) for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" )
for c in self.collection:
x = c[0] if isinstance( c, unicode ) else getattr(c, self.alpha_attribute)[0]
if isinstance(c, unicode):
x = c[0]
elif isinstance(c, dict):
x = c[self.alpha_attribute][0]
else:
x = getattr(c, self.alpha_attribute)[0]
self.available[x] = self.available.get(x, 0) + 1



def pager(self, q=None):
'''Returns pager html - for navigating between the pages.
e.g. Something like this:
Expand Down
8 changes: 4 additions & 4 deletions ckan/lib/authenticator.py
Expand Up @@ -5,7 +5,7 @@

class OpenIDAuthenticator(object):
implements(IAuthenticator)

def authenticate(self, environ, identity):
if 'repoze.who.plugins.openid.userid' in identity:
openid = identity.get('repoze.who.plugins.openid.userid')
Expand All @@ -15,16 +15,16 @@ def authenticate(self, environ, identity):
else:
return user.name
return None


class UsernamePasswordAuthenticator(object):
implements(IAuthenticator)

def authenticate(self, environ, identity):
if not 'login' in identity or not 'password' in identity:
return None
user = User.by_name(identity.get('login'))
if user is None:
if user is None:
return None
if user.validate_password(identity.get('password')):
return user.name
Expand Down

0 comments on commit 4ff47f9

Please sign in to comment.